summaryrefslogtreecommitdiffstats
path: root/win
diff options
context:
space:
mode:
Diffstat (limited to 'win')
-rw-r--r--win/Makefile.in85
-rwxr-xr-xwin/configure64
-rw-r--r--win/configure.in10
-rw-r--r--win/ttkWinMonitor.c164
-rw-r--r--win/ttkWinTheme.c730
-rw-r--r--win/ttkWinXPTheme.c998
6 files changed, 2031 insertions, 20 deletions
diff --git a/win/Makefile.in b/win/Makefile.in
index a2ac0c2..963dcda 100644
--- a/win/Makefile.in
+++ b/win/Makefile.in
@@ -4,7 +4,7 @@
# "autoconf" program (constructs like "@foo@" will get replaced in the
# actual Makefile.
#
-# RCS: @(#) $Id: Makefile.in,v 1.69 2006/09/27 18:43:35 andreas_kupries Exp $
+# RCS: @(#) $Id: Makefile.in,v 1.70 2006/10/31 01:42:27 hobbs Exp $
TCLVERSION = @TCL_VERSION@
TCLPATCHL = @TCL_PATCH_LEVEL@
@@ -113,6 +113,7 @@ ROOT_DIR = $(SRC_DIR)/..
WIN_DIR = $(SRC_DIR)
UNIX_DIR = $(SRC_DIR)/../unix
GENERIC_DIR = $(SRC_DIR)/../generic
+TTK_DIR = $(GENERIC_DIR)/ttk
BITMAP_DIR = $(ROOT_DIR)/bitmaps
XLIB_DIR = $(ROOT_DIR)/xlib
RC_DIR = $(WIN_DIR)/rc
@@ -149,7 +150,7 @@ MAN2TCL = man2tcl$(EXEEXT)
# makefile to look into these paths when resolving .c to .obj
# dependencies.
-VPATH = $(GENERIC_DIR):$(WIN_DIR):$(UNIX_DIR):$(XLIB_DIR):$(RC_DIR)
+VPATH = $(GENERIC_DIR):$(TTK_DIR):$(WIN_DIR):$(UNIX_DIR):$(XLIB_DIR):$(RC_DIR)
# warning flags
CFLAGS_WARNING = @CFLAGS_WARNING@
@@ -346,7 +347,44 @@ TK_OBJS = \
tkVisual.$(OBJEXT) \
tkStubInit.$(OBJEXT) \
tkStubLib.$(OBJEXT) \
- tkWindow.$(OBJEXT)
+ tkWindow.$(OBJEXT) \
+ $(TTK_OBJS)
+
+TTK_OBJS = \
+ ttkWinMonitor.$(OBJEXT) \
+ ttkWinTheme.$(OBJEXT) \
+ ttkWinXPTheme.$(OBJEXT) \
+ ttkBlink.$(OBJEXT) \
+ ttkButton.$(OBJEXT) \
+ ttkCache.$(OBJEXT) \
+ ttkClamTheme.$(OBJEXT) \
+ ttkClassicTheme.$(OBJEXT) \
+ ttkDefaultTheme.$(OBJEXT) \
+ ttkElements.$(OBJEXT) \
+ ttkEntry.$(OBJEXT) \
+ ttkFrame.$(OBJEXT) \
+ ttkImage.$(OBJEXT) \
+ ttkInit.$(OBJEXT) \
+ ttkLabel.$(OBJEXT) \
+ ttkLayout.$(OBJEXT) \
+ ttkManager.$(OBJEXT) \
+ ttkNotebook.$(OBJEXT) \
+ ttkPanedwindow.$(OBJEXT) \
+ ttkProgress.$(OBJEXT) \
+ ttkScale.$(OBJEXT) \
+ ttkScrollbar.$(OBJEXT) \
+ ttkScroll.$(OBJEXT) \
+ ttkSeparator.$(OBJEXT) \
+ ttkSquare.$(OBJEXT) \
+ ttkState.$(OBJEXT) \
+ ttkTagSet.$(OBJEXT) \
+ ttkTheme.$(OBJEXT) \
+ ttkTrace.$(OBJEXT) \
+ ttkTrack.$(OBJEXT) \
+ ttkTreeview.$(OBJEXT) \
+ ttkWidget.$(OBJEXT) \
+ ttkStubInit.$(OBJEXT) \
+ ttkStubLib.$(OBJEXT)
STUB_OBJS = \
tkStubLib.$(OBJEXT) \
@@ -358,6 +396,11 @@ CORE_DOCS = $(TCL_DOCS) $(TK_DOCS)
DEMOPROGS = browse hello ixset rmt rolodex square tcolor timer widget
+SHELL_ENV = \
+ @TCL_LIBRARY="$(TCL_SRC_DIR_NATIVE)/library"; export TCL_LIBRARY; \
+ TK_LIBRARY="$(ROOT_DIR_NATIVE)/library"; export TK_LIBRARY; \
+ PATH="$(TCL_BIN_DIR):$(PATH)"; export PATH;
+
# Main targets. The default target -- all -- builds the binaries,
# performs any post processing on libraries or documents.
@@ -385,26 +428,23 @@ $(MAN2TCL): $(TCL_SRC_DIR_NATIVE)/tools/man2tcl.c
# args to tcltest, ie:
# % make test TESTFLAGS="-verbose bps -file fileName.test"
-test: binaries $(TKTEST)
- @TCL_LIBRARY="$(TCL_SRC_DIR_NATIVE)/library"; export TCL_LIBRARY; \
- TK_LIBRARY="$(ROOT_DIR_NATIVE)/library"; export TK_LIBRARY; \
- PATH="$(TCL_BIN_DIR):$(PATH)"; export PATH; \
- ./$(TKTEST) "$(ROOT_DIR_NATIVE)/tests/all.tcl" $(TESTFLAGS) \
- | ./$(CAT32)
+test: test-classic test-ttk
+
+test-classic: binaries $(TKTEST)
+ $(SHELL_ENV) ./$(TKTEST) "$(ROOT_DIR_NATIVE)/tests/all.tcl" \
+ $(TESTFLAGS) | ./$(CAT32)
+
+test-ttk: binaries $(TKTEST)
+ $(SHELL_ENV) ./$(TKTEST) "$(ROOT_DIR_NATIVE)/tests/ttk/all.tcl" \
+ $(TESTFLAGS) | ./$(CAT32)
runtest: binaries $(TKTEST)
- @TCL_LIBRARY="$(TCL_SRC_DIR_NATIVE)/library"; export TCL_LIBRARY; \
- TK_LIBRARY="$(ROOT_DIR_NATIVE)/library"; export TK_LIBRARY; \
- PATH="$(TCL_BIN_DIR):$(PATH)"; export PATH; \
- ./$(TKTEST) $(TESTFLAGS) $(SCRIPT)
+ $(SHELL_ENV) ./$(TKTEST) $(TESTFLAGS) $(SCRIPT)
# This target can be used to run wish from the build directory
# via `make shell` or `make shell SCRIPT=foo.tcl`
shell: binaries
- @TCL_LIBRARY="$(TCL_SRC_DIR_NATIVE)/library"; export TCL_LIBRARY; \
- TK_LIBRARY="$(ROOT_DIR_NATIVE)/library"; export TK_LIBRARY; \
- PATH="$(TCL_BIN_DIR):$(PATH)"; export PATH; \
- ./$(WISH) $(SCRIPT)
+ $(SHELL_ENV) ./$(WISH) $(SCRIPT)
# This target can be used to run wish inside either gdb or insight
gdb: binaries
@@ -454,7 +494,7 @@ install-libraries: libraries
@for i in $(INSTALL_ROOT)$(prefix)/lib \
$(INCLUDE_INSTALL_DIR) $(INCLUDE_INSTALL_DIR)/X11 \
$(SCRIPT_INSTALL_DIR) $(SCRIPT_INSTALL_DIR)/images \
- $(SCRIPT_INSTALL_DIR)/msgs; \
+ $(SCRIPT_INSTALL_DIR)/msgs $(SCRIPT_INSTALL_DIR)/ttk; \
do \
if [ ! -d $$i ] ; then \
echo "Making directory $$i"; \
@@ -479,6 +519,13 @@ install-libraries: libraries
do \
$(INSTALL_DATA) $$i $(SCRIPT_INSTALL_DIR); \
done;
+ @echo "Installing library ttk directory";
+ @for i in $(ROOT_DIR)/library/ttk/*.tcl; \
+ do \
+ if [ -f $$i ] ; then \
+ $(INSTALL_DATA) $$i $(SCRIPT_INSTALL_DIR)/ttk; \
+ fi; \
+ done;
@echo "Installing library images directory";
@for i in $(ROOT_DIR)/library/images/*; \
do \
@@ -611,7 +658,7 @@ tkSquare.$(OBJEXT): tkSquare.c
# Implicit rule for all object files that will end up in the Tcl library
.c.$(OBJEXT):
- $(CC) -c $(STUB_CC_SWITCHES) -DBUILD_tk @DEPARG@ $(CC_OBJNAME)
+ $(CC) -c $(STUB_CC_SWITCHES) -DBUILD_tk -DBUILD_ttk @DEPARG@ $(CC_OBJNAME)
.rc.$(RES):
$(RC) @RC_OUT@ $@ @RC_TYPE@ @RC_DEFINES@ @RC_INCLUDE@ "$(GENERIC_DIR_NATIVE)" @RC_INCLUDE@ "$(TCL_GENERIC_NATIVE)" @RC_INCLUDE@ "$(TCL_PLATFORM_NATIVE)" @RC_INCLUDE@ "$(RC_DIR_NATIVE)" @DEPARG@
diff --git a/win/configure b/win/configure
index a2b911c..8a3063c 100755
--- a/win/configure
+++ b/win/configure
@@ -3727,6 +3727,70 @@ fi
#--------------------------------------------------------------------
+# Windows XP theme engine header for Ttk
+#--------------------------------------------------------------------
+
+echo "$as_me:$LINENO: checking for uxtheme.h" >&5
+echo $ECHO_N "checking for uxtheme.h... $ECHO_C" >&6
+if test "${ac_cv_header_uxtheme_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <windows.h>
+
+#include <uxtheme.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_uxtheme_h=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_uxtheme_h=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_uxtheme_h" >&5
+echo "${ECHO_T}$ac_cv_header_uxtheme_h" >&6
+if test $ac_cv_header_uxtheme_h = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_UXTHEME_H 1
+_ACEOF
+
+else
+ { echo "$as_me:$LINENO: xpnative theme will be unavailable" >&5
+echo "$as_me: xpnative theme will be unavailable" >&6;}
+fi
+
+
+
+#--------------------------------------------------------------------
# Set the default compiler switches based on the --enable-symbols
# option. This macro depends on C flags, and should be called
# after SC_CONFIG_CFLAGS macro is called.
diff --git a/win/configure.in b/win/configure.in
index 232eb29..601c3f6 100644
--- a/win/configure.in
+++ b/win/configure.in
@@ -3,7 +3,7 @@
# generate the file "configure", which is run during Tk installation
# to configure the system for the local environment.
#
-# RCS: @(#) $Id: configure.in,v 1.64 2006/10/23 19:46:14 dgp Exp $
+# RCS: @(#) $Id: configure.in,v 1.65 2006/10/31 01:42:28 hobbs Exp $
AC_INIT(../generic/tk.h)
AC_PREREQ(2.59)
@@ -138,6 +138,14 @@ AC_CHECK_HEADER(errno.h, , MAN2TCLFLAGS="-DNO_ERRNO_H")
AC_SUBST(MAN2TCLFLAGS)
#--------------------------------------------------------------------
+# Windows XP theme engine header for Ttk
+#--------------------------------------------------------------------
+
+AC_CHECK_HEADER([uxtheme.h], [AC_DEFINE(HAVE_UXTHEME_H)],
+ [AC_MSG_NOTICE([xpnative theme will be unavailable])],
+ [#include <windows.h>])
+
+#--------------------------------------------------------------------
# Set the default compiler switches based on the --enable-symbols
# option. This macro depends on C flags, and should be called
# after SC_CONFIG_CFLAGS macro is called.
diff --git a/win/ttkWinMonitor.c b/win/ttkWinMonitor.c
new file mode 100644
index 0000000..b13c36d
--- /dev/null
+++ b/win/ttkWinMonitor.c
@@ -0,0 +1,164 @@
+/* $Id: ttkWinMonitor.c,v 1.1 2006/10/31 01:42:28 hobbs Exp $
+ */
+
+#ifdef _MSC_VER
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#include <windows.h>
+#include <tcl.h>
+#include <tk.h>
+#include <tkPlatDecls.h>
+#include "ttk/ttkTheme.h"
+
+#if !defined(WM_THEMECHANGED)
+#define WM_THEMECHANGED 0x031A
+#endif
+
+static LRESULT WINAPI WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
+
+/*
+ * RegisterSystemColors --
+ * Register all known Windows system colors (as per GetSysColor)
+ * as Tk named colors.
+ */
+
+typedef struct {
+ const char *name;
+ int index;
+} SystemColorEntry;
+
+static SystemColorEntry sysColors[] = {
+ { "System3dDarkShadow", COLOR_3DDKSHADOW },
+ { "System3dLight", COLOR_3DLIGHT },
+ { "SystemActiveBorder", COLOR_ACTIVEBORDER },
+ { "SystemActiveCaption", COLOR_ACTIVECAPTION },
+ { "SystemAppWorkspace", COLOR_APPWORKSPACE },
+ { "SystemBackground", COLOR_BACKGROUND },
+ { "SystemButtonFace", COLOR_BTNFACE },
+ { "SystemButtonHighlight", COLOR_BTNHIGHLIGHT },
+ { "SystemButtonShadow", COLOR_BTNSHADOW },
+ { "SystemButtonText", COLOR_BTNTEXT },
+ { "SystemCaptionText", COLOR_CAPTIONTEXT },
+ { "SystemDisabledText", COLOR_GRAYTEXT },
+ { "SystemGrayText", COLOR_GRAYTEXT },
+ { "SystemHighlight", COLOR_HIGHLIGHT },
+ { "SystemHighlightText", COLOR_HIGHLIGHTTEXT },
+ { "SystemInactiveBorder", COLOR_INACTIVEBORDER },
+ { "SystemInactiveCaption", COLOR_INACTIVECAPTION },
+ { "SystemInactiveCaptionText", COLOR_INACTIVECAPTIONTEXT },
+ { "SystemInfoBackground", COLOR_INFOBK },
+ { "SystemInfoText", COLOR_INFOTEXT },
+ { "SystemMenu", COLOR_MENU },
+ { "SystemMenuText", COLOR_MENUTEXT },
+ { "SystemScrollbar", COLOR_SCROLLBAR },
+ { "SystemWindow", COLOR_WINDOW },
+ { "SystemWindowFrame", COLOR_WINDOWFRAME },
+ { "SystemWindowText", COLOR_WINDOWTEXT },
+ { NULL, 0 }
+};
+
+static void RegisterSystemColors(Tcl_Interp *interp)
+{
+ Ttk_ResourceCache cache = Ttk_GetResourceCache(interp);
+ SystemColorEntry *sysColor;
+
+ for (sysColor = sysColors; sysColor->name; ++sysColor) {
+ DWORD pixel = GetSysColor(sysColor->index);
+ XColor colorSpec;
+ colorSpec.red = GetRValue(pixel) * 257;
+ colorSpec.green = GetGValue(pixel) * 257;
+ colorSpec.blue = GetBValue(pixel) * 257;
+ Ttk_RegisterNamedColor(cache, sysColor->name, &colorSpec);
+ }
+}
+
+static HWND
+CreateThemeMonitorWindow(HINSTANCE hinst, Tcl_Interp *interp)
+{
+ WNDCLASSEX wc;
+ HWND hwnd = NULL;
+ CHAR title[32] = "TtkMonitorWindow";
+ CHAR name[32] = "TtkMonitorClass";
+
+ wc.cbSize = sizeof(WNDCLASSEX);
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = (WNDPROC)WndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hinst;
+ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
+ wc.lpszMenuName = name;
+ wc.lpszClassName = name;
+
+ if (RegisterClassEx(&wc)) {
+ hwnd = CreateWindow( name, title, WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ NULL, NULL, hinst, NULL );
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG)interp);
+ ShowWindow(hwnd, SW_HIDE);
+ UpdateWindow(hwnd);
+ }
+ return hwnd;
+}
+
+static void
+DestroyThemeMonitorWindow(void *clientData)
+{
+ HWND hwnd = (HWND)clientData;
+ DestroyWindow(hwnd);
+}
+
+static LRESULT WINAPI
+WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ Tcl_Interp *interp = (Tcl_Interp *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ Ttk_Theme theme;
+
+ switch (msg) {
+ case WM_DESTROY:
+ break;
+
+ case WM_SYSCOLORCHANGE:
+ RegisterSystemColors(interp);
+ break;
+
+ case WM_THEMECHANGED:
+ /*
+ * Reset the application theme to 'xpnative' if present,
+ * which will in turn fall back to 'winnative' if XP theming
+ * is disabled.
+ */
+ theme = Ttk_GetTheme(interp, "xpnative");
+ if (theme) {
+ Ttk_UseTheme(interp, theme);
+ /* @@@ What to do about errors here? */
+ }
+ break;
+ }
+ return DefWindowProc(hwnd, msg, wp, lp);
+}
+
+/*
+ * Windows-specific platform initialization:
+ */
+
+extern int WinTheme_Init(Tcl_Interp *, HWND hwnd);
+extern int XPTheme_Init(Tcl_Interp *, HWND hwnd);
+
+int Ttk_WinPlatformInit(Tcl_Interp *interp)
+{
+ HWND hwnd;
+
+ hwnd = CreateThemeMonitorWindow(Tk_GetHINSTANCE(), interp);
+ Ttk_RegisterCleanup(interp, (ClientData)hwnd, DestroyThemeMonitorWindow);
+
+ WinTheme_Init(interp, hwnd);
+ XPTheme_Init(interp, hwnd);
+
+ return TCL_OK;
+}
+
diff --git a/win/ttkWinTheme.c b/win/ttkWinTheme.c
new file mode 100644
index 0000000..eb3a9eb
--- /dev/null
+++ b/win/ttkWinTheme.c
@@ -0,0 +1,730 @@
+/* winTheme.c - Copyright (C) 2004 Pat Thoyts <patthoyts@users.sf.net>
+ *
+ * $Id: ttkWinTheme.c,v 1.1 2006/10/31 01:42:28 hobbs Exp $
+ */
+
+#ifdef _MSC_VER
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#include <windows.h>
+
+#include <tk.h>
+#include <tkWinInt.h>
+
+#ifndef DFCS_HOT /* Windows 98/Me, Windows 200/XP only */
+#define DFCS_HOT 0
+#endif
+
+#include "ttk/ttkTheme.h"
+
+/*
+ * BoxToRect --
+ * Helper routine. Converts a Ttk_Box to a Win32 RECT.
+ */
+static RECT BoxToRect(Ttk_Box b)
+{
+ RECT rc;
+ rc.top = b.y;
+ rc.left = b.x;
+ rc.bottom = b.y + b.height;
+ rc.right = b.x + b.width;
+ return rc;
+}
+
+/*
+ * ReliefToEdge --
+ * Convert a Tk "relief" value into an Windows "edge" value.
+ * NB: Caller must check for RELIEF_FLAT and RELIEF_SOLID,
+ * which must be handled specially.
+ *
+ * Passing the BF_FLAT flag to DrawEdge() yields something similar
+ * to TK_RELIEF_SOLID. TK_RELIEF_FLAT can be implemented by not
+ * drawing anything.
+ */
+static unsigned int ReliefToEdge(int relief)
+{
+ switch (relief) {
+ case TK_RELIEF_RAISED: return EDGE_RAISED;
+ case TK_RELIEF_SUNKEN: return EDGE_SUNKEN;
+ case TK_RELIEF_RIDGE: return EDGE_BUMP;
+ case TK_RELIEF_GROOVE: return EDGE_ETCHED;
+ case TK_RELIEF_SOLID: return BDR_RAISEDOUTER;
+ default:
+ case TK_RELIEF_FLAT: return BDR_RAISEDOUTER;
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+
+static Ttk_StateTable checkbutton_statemap[] =
+{
+ { DFCS_CHECKED|DFCS_INACTIVE, TTK_STATE_SELECTED|TTK_STATE_DISABLED, 0 },
+ { DFCS_CHECKED|DFCS_PUSHED, TTK_STATE_SELECTED|TTK_STATE_PRESSED, 0 },
+ { DFCS_CHECKED, TTK_STATE_SELECTED, 0 },
+ { DFCS_INACTIVE, TTK_STATE_DISABLED, TTK_STATE_SELECTED },
+ { DFCS_PUSHED, TTK_STATE_PRESSED, TTK_STATE_SELECTED},
+ { 0, 0, 0 }
+};
+
+static Ttk_StateTable pushbutton_statemap[] =
+{
+ { DFCS_INACTIVE, TTK_STATE_DISABLED, 0 },
+ { DFCS_PUSHED, TTK_STATE_PRESSED, 0 },
+ { DFCS_HOT, TTK_STATE_ACTIVE, 0 },
+ { 0, 0, 0 }
+};
+
+static Ttk_StateTable arrow_statemap[] =
+{
+ { DFCS_INACTIVE, TTK_STATE_DISABLED, 0 },
+ { DFCS_PUSHED | DFCS_FLAT, TTK_STATE_PRESSED, 0 },
+ { 0, 0, 0 }
+};
+
+/*------------------------------------------------------------------------
+ * +++ FrameControlElement --
+ * General-purpose element for things drawn with DrawFrameControl
+ */
+typedef struct
+{
+ const char *name; /* element name */
+ int classId; /* class id for DrawFrameControl */
+ int partId; /* part id for DrawFrameControl */
+ int cxId; /* system metric id for size in x */
+ int cyId; /* system metric id for size in y */
+ Ttk_StateTable *stateMap; /* map Tk states to Win32 flags */
+ Ttk_Padding padding; /* additional placement padding */
+} FrameControlElementData;
+
+static FrameControlElementData FrameControlElements[] =
+{
+ { "Checkbutton.indicator",
+ DFC_BUTTON, DFCS_BUTTONCHECK, SM_CYMENUCHECK, SM_CYMENUCHECK,
+ checkbutton_statemap, {0,0,4,0} },
+ { "Radiobutton.indicator",
+ DFC_BUTTON, DFCS_BUTTONRADIO, SM_CYMENUCHECK, SM_CYMENUCHECK,
+ checkbutton_statemap, {0,0,4,0} },
+ { "uparrow",
+ DFC_SCROLL, DFCS_SCROLLUP, SM_CXVSCROLL, SM_CYVSCROLL,
+ arrow_statemap, {0,0,0,0} },
+ { "downarrow",
+ DFC_SCROLL, DFCS_SCROLLDOWN, SM_CXVSCROLL, SM_CYVSCROLL,
+ arrow_statemap, {0,0,0,0} },
+ { "leftarrow",
+ DFC_SCROLL, DFCS_SCROLLLEFT, SM_CXHSCROLL, SM_CYHSCROLL,
+ arrow_statemap, {0,0,0,0} },
+ { "rightarrow",
+ DFC_SCROLL, DFCS_SCROLLRIGHT, SM_CXHSCROLL, SM_CYHSCROLL,
+ arrow_statemap, {0,0,0,0} },
+ { "sizegrip",
+ DFC_SCROLL, DFCS_SCROLLSIZEGRIP, SM_CXVSCROLL, SM_CYHSCROLL,
+ arrow_statemap, {0,0,0,0} },
+
+ { 0,0,0,0,0,0, {0,0,0,0} }
+};
+
+/* ---------------------------------------------------------------------- */
+
+static void FrameControlElementGeometry(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
+{
+ FrameControlElementData *elementData = clientData;
+ *widthPtr = GetSystemMetrics(elementData->cxId);
+ *heightPtr = GetSystemMetrics(elementData->cyId);
+ *paddingPtr = elementData->padding;
+}
+
+static void FrameControlElementDraw(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, unsigned int state)
+{
+ FrameControlElementData *elementData = clientData;
+ RECT rc = BoxToRect(b);
+ TkWinDCState dcState;
+ HDC hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
+
+ DrawFrameControl(hdc, &rc,
+ elementData->classId,
+ elementData->partId|Ttk_StateTableLookup(elementData->stateMap, state));
+ TkWinReleaseDrawableDC(d, hdc, &dcState);
+}
+
+static Ttk_ElementSpec FrameControlElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(NullElement),
+ NullElementOptions,
+ FrameControlElementGeometry,
+ FrameControlElementDraw
+};
+
+/*----------------------------------------------------------------------
+ * +++ Border element implementation.
+ */
+
+typedef struct {
+ Tcl_Obj *reliefObj;
+} BorderElement;
+
+static Ttk_ElementOptionSpec BorderElementOptions[] = {
+ { "-relief",TK_OPTION_RELIEF,Tk_Offset(BorderElement,reliefObj), "flat" },
+ {NULL}
+};
+
+static void BorderElementGeometry(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
+{
+ paddingPtr->left = paddingPtr->right = GetSystemMetrics(SM_CXEDGE);
+ paddingPtr->top = paddingPtr->bottom = GetSystemMetrics(SM_CYEDGE);
+}
+
+static void BorderElementDraw(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, unsigned int state)
+{
+ BorderElement *border = elementRecord;
+ RECT rc = BoxToRect(b);
+ int relief = TK_RELIEF_FLAT;
+ TkWinDCState dcState;
+ HDC hdc;
+
+ Tk_GetReliefFromObj(NULL, border->reliefObj, &relief);
+
+ if (relief != TK_RELIEF_FLAT) {
+ UINT xFlags = (relief == TK_RELIEF_SOLID) ? BF_FLAT : 0;
+ hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
+ DrawEdge(hdc, &rc, ReliefToEdge(relief), BF_RECT | xFlags);
+ TkWinReleaseDrawableDC(d, hdc, &dcState);
+ }
+}
+
+static Ttk_ElementSpec BorderElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(BorderElement),
+ BorderElementOptions,
+ BorderElementGeometry,
+ BorderElementDraw
+};
+
+/*
+ * Entry field borders:
+ * Sunken border; also fill with window color.
+ */
+
+typedef struct
+{
+ Tcl_Obj *backgroundObj;
+} FieldElement;
+
+static Ttk_ElementOptionSpec FieldElementOptions[] =
+{
+ { "-fieldbackground", TK_OPTION_BORDER,
+ Tk_Offset(FieldElement,backgroundObj), "white" },
+ {NULL}
+};
+
+static void
+FieldElementGeometry(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
+{
+ paddingPtr->left = paddingPtr->right = GetSystemMetrics(SM_CXEDGE);
+ paddingPtr->top = paddingPtr->bottom = GetSystemMetrics(SM_CYEDGE);
+}
+
+static void
+FieldElementDraw(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, unsigned int state)
+{
+ FieldElement *field = elementRecord;
+ Tk_3DBorder bg = Tk_Get3DBorderFromObj(tkwin, field->backgroundObj);
+ RECT rc = BoxToRect(b);
+ TkWinDCState dcState;
+ HDC hdc;
+
+ Tk_Fill3DRectangle(
+ tkwin, d, bg, b.x, b.y, b.width, b.height, 0, TK_RELIEF_FLAT);
+
+ hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
+ DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_RECT);
+ TkWinReleaseDrawableDC(d, hdc, &dcState);
+}
+
+static Ttk_ElementSpec FieldElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(FieldElement),
+ FieldElementOptions,
+ FieldElementGeometry,
+ FieldElementDraw
+};
+
+/*------------------------------------------------------------------------
+ * +++ Button borders.
+ * Drawn with DrawFrameControl instead of DrawEdge;
+ * Also draw default indicator and focus ring.
+ */
+typedef struct {
+ Tcl_Obj *reliefObj;
+ Tcl_Obj *highlightColorObj;
+ Tcl_Obj *defaultStateObj;
+} ButtonBorderElement;
+
+static Ttk_ElementOptionSpec ButtonBorderElementOptions[] = {
+ { "-relief",TK_OPTION_RELIEF,
+ Tk_Offset(ButtonBorderElement,reliefObj), "flat" },
+ { "-highlightcolor",TK_OPTION_COLOR,
+ Tk_Offset(ButtonBorderElement,highlightColorObj), "black" },
+ { "-default", TK_OPTION_ANY,
+ Tk_Offset(ButtonBorderElement,defaultStateObj), "disabled" },
+ {NULL}
+};
+
+static void ButtonBorderElementGeometry(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
+{
+ ButtonBorderElement *bd = elementRecord;
+ int relief = TK_RELIEF_RAISED;
+ int defaultState = TTK_BUTTON_DEFAULT_DISABLED;
+ short int cx, cy;
+
+ Tk_GetReliefFromObj(NULL, bd->reliefObj, &relief);
+ Ttk_GetButtonDefaultStateFromObj(NULL, bd->defaultStateObj, &defaultState);
+ cx = GetSystemMetrics(SM_CXEDGE);
+ cy = GetSystemMetrics(SM_CYEDGE);
+
+ /* Space for default indicator:
+ */
+ if (defaultState != TTK_BUTTON_DEFAULT_DISABLED) {
+ ++cx; ++cy;
+ }
+
+ /* Space for focus ring:
+ */
+ cx += 2;
+ cy += 2;
+
+ *paddingPtr = Ttk_MakePadding(cx,cy,cx,cy);
+}
+
+static void ButtonBorderElementDraw(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, unsigned int state)
+{
+ ButtonBorderElement *bd = elementRecord;
+ int relief = TK_RELIEF_FLAT;
+ int defaultState = TTK_BUTTON_DEFAULT_DISABLED;
+ TkWinDCState dcState;
+ HDC hdc;
+ RECT rc;
+
+ Tk_GetReliefFromObj(NULL, bd->reliefObj, &relief);
+ Ttk_GetButtonDefaultStateFromObj(NULL, bd->defaultStateObj, &defaultState);
+
+ if (defaultState == TTK_BUTTON_DEFAULT_ACTIVE) {
+ XColor *highlightColor =
+ Tk_GetColorFromObj(tkwin, bd->highlightColorObj);
+ GC gc = Tk_GCForColor(highlightColor, d);
+ XDrawRectangle(Tk_Display(tkwin), d, gc, b.x,b.y,b.width-1,b.height-1);
+ }
+ if (defaultState != TTK_BUTTON_DEFAULT_DISABLED) {
+ ++b.x; ++b.y; b.width -= 2; b.height -= 2;
+ }
+
+ hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
+
+ rc = BoxToRect(b);
+ DrawFrameControl(hdc, &rc,
+ DFC_BUTTON, /* classId */
+ DFCS_BUTTONPUSH | Ttk_StateTableLookup(pushbutton_statemap, state));
+
+ /* Draw focus ring:
+ */
+ if (state & TTK_STATE_FOCUS) {
+ short int borderWidth = 3; /* @@@ Use GetSystemMetrics?*/
+ rc = BoxToRect(Ttk_PadBox(b, Ttk_UniformPadding(borderWidth)));
+ DrawFocusRect(hdc, &rc);
+ }
+ TkWinReleaseDrawableDC(d, hdc, &dcState);
+}
+
+static Ttk_ElementSpec ButtonBorderElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(ButtonBorderElement),
+ ButtonBorderElementOptions,
+ ButtonBorderElementGeometry,
+ ButtonBorderElementDraw
+};
+
+/*------------------------------------------------------------------------
+ * +++ Focus element.
+ * Draw dashed focus rectangle.
+ */
+
+static void FocusElementGeometry(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
+{
+ *paddingPtr = Ttk_UniformPadding(1);
+}
+
+static void FocusElementDraw(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, unsigned int state)
+{
+ if (state & TTK_STATE_FOCUS) {
+ RECT rc = BoxToRect(b);
+ TkWinDCState dcState;
+ HDC hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
+ DrawFocusRect(hdc, &rc);
+ TkWinReleaseDrawableDC(d, hdc, &dcState);
+ }
+}
+
+static Ttk_ElementSpec FocusElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(NullElement),
+ NullElementOptions,
+ FocusElementGeometry,
+ FocusElementDraw
+};
+
+/* FillFocusElement --
+ * Draws a focus ring filled with the selection color
+ */
+
+typedef struct {
+ Tcl_Obj *fillColorObj;
+} FillFocusElement;
+
+static Ttk_ElementOptionSpec FillFocusElementOptions[] = {
+ { "-focusfill", TK_OPTION_COLOR,
+ Tk_Offset(FillFocusElement,fillColorObj), "white" },
+ { NULL }
+};
+
+ /* @@@ FIX THIS */
+static void FillFocusElementDraw(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, unsigned int state)
+{
+ FillFocusElement *focus = elementRecord;
+ if (state & TTK_STATE_FOCUS) {
+ RECT rc = BoxToRect(b);
+ TkWinDCState dcState;
+ XColor *fillColor = Tk_GetColorFromObj(tkwin, focus->fillColorObj);
+ GC gc = Tk_GCForColor(fillColor, d);
+ HDC hdc;
+
+ XFillRectangle(Tk_Display(tkwin),d,gc, b.x,b.y,b.width,b.height);
+ hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
+ DrawFocusRect(hdc, &rc);
+ TkWinReleaseDrawableDC(d, hdc, &dcState);
+ }
+}
+
+/*
+ * ComboboxFocusElement --
+ * Read-only comboboxes have a filled focus ring, editable ones do not.
+ */
+static void ComboboxFocusElementDraw(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, unsigned int state)
+{
+ if (state & TTK_STATE_READONLY) {
+ FillFocusElementDraw(clientData, elementRecord, tkwin, d, b, state);
+ }
+}
+
+static Ttk_ElementSpec ComboboxFocusElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(FillFocusElement),
+ FillFocusElementOptions,
+ FocusElementGeometry,
+ ComboboxFocusElementDraw
+};
+
+/*----------------------------------------------------------------------
+ * +++ Scrollbar trough element.
+ *
+ * The native windows scrollbar is drawn using a pattern brush giving a
+ * stippled appearance when the trough might otherwise be invisible.
+ * We can deal with this here.
+ */
+
+typedef struct { /* clientData for Trough element */
+ HBRUSH PatternBrush;
+ HBITMAP PatternBitmap;
+} TroughClientData;
+
+static const WORD Pattern[] = {
+ 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa
+};
+
+static void TroughClientDataDeleteProc(void *clientData)
+{
+ TroughClientData *cd = clientData;
+ DeleteObject(cd->PatternBrush);
+ DeleteObject(cd->PatternBitmap);
+ ckfree(clientData);
+}
+
+static TroughClientData *TroughClientDataInit(Tcl_Interp *interp)
+{
+ TroughClientData *cd = (TroughClientData*)ckalloc(sizeof(*cd));
+ cd->PatternBitmap = CreateBitmap(8, 8, 1, 1, Pattern);
+ cd->PatternBrush = CreatePatternBrush(cd->PatternBitmap);
+ Ttk_RegisterCleanup(interp, cd, TroughClientDataDeleteProc);
+ return cd;
+}
+
+static void TroughElementDraw(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, unsigned int state)
+{
+ TroughClientData *cd = clientData;
+ TkWinDCState dcState;
+ HDC hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
+ HBRUSH hbr;
+ COLORREF bk, oldbk, oldtxt;
+
+ hbr = SelectObject(hdc, GetSysColorBrush(COLOR_SCROLLBAR));
+ bk = GetSysColor(COLOR_3DHIGHLIGHT);
+ oldtxt = SetTextColor(hdc, GetSysColor(COLOR_3DFACE));
+ oldbk = SetBkColor(hdc, bk);
+
+ /* WAS: if (bk (COLOR_3DHIGHLIGHT) == GetSysColor(COLOR_WINDOW)) ... */
+ if (GetSysColor(COLOR_SCROLLBAR) == GetSysColor(COLOR_BTNFACE)) {
+ /* Draw using the pattern brush */
+ SelectObject(hdc, cd->PatternBrush);
+ }
+
+ PatBlt(hdc, b.x, b.y, b.width, b.height, PATCOPY);
+ SetBkColor(hdc, oldbk);
+ SetTextColor(hdc, oldtxt);
+ SelectObject(hdc, hbr);
+ TkWinReleaseDrawableDC(d, hdc, &dcState);
+}
+
+static Ttk_ElementSpec TroughElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(NullElement),
+ NullElementOptions,
+ NullElementGeometry,
+ TroughElementDraw
+};
+
+/*------------------------------------------------------------------------
+ * +++ Thumb element.
+ */
+
+typedef struct
+{
+ Tcl_Obj *orientObj;
+} ThumbElement;
+
+static Ttk_ElementOptionSpec ThumbElementOptions[] =
+{
+ { "-orient", TK_OPTION_ANY,Tk_Offset(ThumbElement,orientObj),"horizontal"},
+ { NULL }
+};
+
+static void ThumbElementGeometry(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
+{
+ ThumbElement *thumbPtr = elementRecord;
+ int orient;
+
+ Ttk_GetOrientFromObj(NULL, thumbPtr->orientObj, &orient);
+ if (orient == TTK_ORIENT_HORIZONTAL) {
+ *widthPtr = GetSystemMetrics(SM_CXHTHUMB);
+ *heightPtr = GetSystemMetrics(SM_CYHSCROLL);
+ } else {
+ *widthPtr = GetSystemMetrics(SM_CXVSCROLL);
+ *heightPtr = GetSystemMetrics(SM_CYVTHUMB);
+ }
+}
+
+static void ThumbElementDraw(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, unsigned int state)
+{
+ RECT rc = BoxToRect(b);
+ TkWinDCState dcState;
+ HDC hdc;
+
+ /* Windows doesn't show a thumb when the scrollbar is disabled */
+ if (state & TTK_STATE_DISABLED)
+ return;
+
+ hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
+ DrawEdge(hdc, &rc, EDGE_RAISED, BF_RECT | BF_MIDDLE);
+ TkWinReleaseDrawableDC(d, hdc, &dcState);
+}
+
+static Ttk_ElementSpec ThumbElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(ThumbElement),
+ ThumbElementOptions,
+ ThumbElementGeometry,
+ ThumbElementDraw
+};
+
+/* ----------------------------------------------------------------------
+ * The slider element is the shaped thumb used in the slider widget.
+ * Windows likes to call this a trackbar.
+ */
+
+typedef struct
+{
+ Tcl_Obj *orientObj; /* orientation of the slider widget */
+} SliderElement;
+
+static Ttk_ElementOptionSpec SliderElementOptions[] =
+{
+ { "-orient", TK_OPTION_ANY, Tk_Offset(SliderElement,orientObj),
+ "horizontal" },
+ { NULL }
+};
+
+static void SliderElementGeometry(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
+{
+ SliderElement *slider = elementRecord;
+ int orient;
+
+ Ttk_GetOrientFromObj(NULL, slider->orientObj, &orient);
+ if (orient == TTK_ORIENT_HORIZONTAL) {
+ *widthPtr = (GetSystemMetrics(SM_CXHTHUMB) / 2) | 1;
+ *heightPtr = GetSystemMetrics(SM_CYHSCROLL);
+ } else {
+ *widthPtr = GetSystemMetrics(SM_CXVSCROLL);
+ *heightPtr = (GetSystemMetrics(SM_CYVTHUMB) / 2) | 1;
+ }
+}
+
+static void SliderElementDraw(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, unsigned int state)
+{
+ RECT rc = BoxToRect(b);
+ TkWinDCState dcState;
+ HDC hdc;
+
+ hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
+ DrawEdge(hdc, &rc, EDGE_RAISED, BF_RECT | BF_MIDDLE);
+ TkWinReleaseDrawableDC(d, hdc, &dcState);
+}
+
+static Ttk_ElementSpec SliderElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(SliderElement),
+ SliderElementOptions,
+ SliderElementGeometry,
+ SliderElementDraw
+};
+
+/*------------------------------------------------------------------------
+ * +++ Notebook elements.
+ */
+
+static void ClientElementGeometry(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
+{
+ paddingPtr->left = paddingPtr->right = GetSystemMetrics(SM_CXEDGE);
+ paddingPtr->top = paddingPtr->bottom = GetSystemMetrics(SM_CYEDGE);
+}
+
+static void ClientElementDraw(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, unsigned int state)
+{
+ RECT rc = BoxToRect(b);
+ TkWinDCState dcState;
+ HDC hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
+ DrawEdge(hdc, &rc, EDGE_RAISED, BF_RECT | BF_SOFT);
+ TkWinReleaseDrawableDC(d, hdc, &dcState);
+}
+
+static Ttk_ElementSpec ClientElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(NullElement),
+ NullElementOptions,
+ ClientElementGeometry,
+ ClientElementDraw
+};
+
+/*------------------------------------------------------------------------
+ * +++ Layouts.
+ */
+
+TTK_BEGIN_LAYOUT(ButtonLayout)
+ TTK_GROUP("Button.border", TTK_FILL_BOTH,
+ TTK_GROUP("Button.padding", TTK_FILL_BOTH,
+ TTK_NODE("Button.label", TTK_FILL_BOTH)))
+TTK_END_LAYOUT
+
+TTK_BEGIN_LAYOUT(ComboboxLayout)
+ TTK_GROUP("Combobox.field", TTK_FILL_BOTH,
+ TTK_NODE("Combobox.downarrow", TTK_PACK_RIGHT|TTK_FILL_Y)
+ TTK_GROUP("Combobox.padding", TTK_PACK_LEFT|TTK_EXPAND|TTK_FILL_BOTH,
+ TTK_GROUP("Combobox.focus", TTK_PACK_LEFT|TTK_EXPAND|TTK_FILL_BOTH,
+ TTK_NODE("Combobox.textarea", TTK_FILL_BOTH))))
+TTK_END_LAYOUT
+
+
+/* ---------------------------------------------------------------------- */
+
+int WinTheme_Init(Tcl_Interp *interp, HWND hwnd)
+{
+ Ttk_Theme themePtr, parentPtr;
+ FrameControlElementData *fce = FrameControlElements;
+
+ parentPtr = Ttk_GetTheme(interp, "alt");
+ themePtr = Ttk_CreateTheme(interp, "winnative", parentPtr);
+ if (!themePtr) {
+ return TCL_ERROR;
+ }
+
+ Ttk_RegisterElementSpec(themePtr, "border", &BorderElementSpec, NULL);
+ Ttk_RegisterElementSpec(themePtr, "Button.border",
+ &ButtonBorderElementSpec, NULL);
+ Ttk_RegisterElementSpec(themePtr, "field", &FieldElementSpec, NULL);
+ Ttk_RegisterElementSpec(themePtr, "focus", &FocusElementSpec, NULL);
+ Ttk_RegisterElementSpec(themePtr, "Combobox.focus",
+ &ComboboxFocusElementSpec, NULL);
+ Ttk_RegisterElementSpec(themePtr, "thumb", &ThumbElementSpec, NULL);
+ Ttk_RegisterElementSpec(themePtr, "slider", &SliderElementSpec, NULL);
+ Ttk_RegisterElementSpec(themePtr, "Scrollbar.trough", &TroughElementSpec,
+ TroughClientDataInit(interp));
+
+ Ttk_RegisterElementSpec(themePtr, "client", &ClientElementSpec, NULL);
+
+ for (fce = FrameControlElements; fce->name != 0; ++fce) {
+ Ttk_RegisterElementSpec(themePtr, fce->name,
+ &FrameControlElementSpec, fce);
+ }
+
+ Ttk_RegisterLayout(themePtr, "TButton", ButtonLayout);
+ Ttk_RegisterLayout(themePtr, "TCombobox", ComboboxLayout);
+
+ Tcl_PkgProvide(interp, "ttk::theme::winnative", TTK_VERSION);
+ return TCL_OK;
+}
+
diff --git a/win/ttkWinXPTheme.c b/win/ttkWinXPTheme.c
new file mode 100644
index 0000000..107aa55
--- /dev/null
+++ b/win/ttkWinXPTheme.c
@@ -0,0 +1,998 @@
+/*
+ * $Id: ttkWinXPTheme.c,v 1.1 2006/10/31 01:42:28 hobbs Exp $
+ *
+ * Tk theme engine which uses the Windows XP "Visual Styles" API
+ * Adapted from Georgios Petasis' XP theme patch.
+ *
+ * Copyright (c) 2003 by Georgios Petasis, petasis@iit.demokritos.gr.
+ * Copyright (c) 2003 by Joe English
+ * Copyright (c) 2003 by Pat Thoyts
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * See also:
+ *
+ * <URL: http://msdn.microsoft.com/library/en-us/
+ * shellcc/platform/commctls/userex/refentry.asp >
+ */
+
+#ifndef HAVE_UXTHEME_H
+/* Stub for platforms that lack the XP theme API headers: */
+#include <windows.h>
+#include <tcl.h>
+int XPTheme_Init(Tcl_Interp *interp, HWND hwnd) { return TCL_OK; }
+#else
+
+#define WINVER 0x0501 /* Requires Windows XP APIs */
+
+#include <windows.h>
+#include <uxtheme.h>
+#include <tmschema.h>
+
+#include <tkWinInt.h>
+
+#include "ttk/ttkTheme.h"
+
+typedef HTHEME (STDAPICALLTYPE OpenThemeDataProc)(HWND hwnd,
+ LPCWSTR pszClassList);
+typedef HRESULT (STDAPICALLTYPE CloseThemeDataProc)(HTHEME hTheme);
+typedef HRESULT (STDAPICALLTYPE DrawThemeBackgroundProc)(HTHEME hTheme,
+ HDC hdc, int iPartId, int iStateId, const RECT *pRect,
+ OPTIONAL const RECT *pClipRect);
+typedef HRESULT (STDAPICALLTYPE DrawThemeParentBackgroundProc)(HWND hwnd,
+ HDC hdc, OPTIONAL const RECT *prc);
+typedef HRESULT (STDAPICALLTYPE DrawThemeEdgeProc)(HTHEME hTheme, HDC hdc,
+ int iPartId, int iStateId, const RECT *pDestRect,
+ UINT uEdge, UINT uFlags, RECT *pContentRect);
+typedef HRESULT (STDAPICALLTYPE DrawThemeTextProc)(HTHEME hTheme, HDC hdc,
+ int iPartId, int iStateId, LPCWSTR pszText, int iCharCount,
+ DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect);
+typedef HRESULT (STDAPICALLTYPE GetThemeMarginsProc)(HTHEME, HDC,
+ int iPartId, int iStateId, int iPropId,
+ OPTIONAL RECT *prc, MARGINS *pMargins);
+typedef HRESULT (STDAPICALLTYPE GetThemePartSizeProc)(HTHEME,HDC,
+ int iPartId, int iStateId,
+ RECT *prc, enum THEMESIZE eSize, SIZE *psz);
+typedef HRESULT (STDAPICALLTYPE GetThemeTextExtentProc)(HTHEME hTheme, HDC hdc,
+ int iPartId, int iStateId, LPCWSTR pszText, int iCharCount,
+ DWORD dwTextFlags, const RECT *pBoundingRect, RECT *pExtentRect);
+typedef BOOL (STDAPICALLTYPE IsThemeActiveProc)(VOID);
+
+typedef struct
+{
+ OpenThemeDataProc *OpenThemeData;
+ CloseThemeDataProc *CloseThemeData;
+ DrawThemeBackgroundProc *DrawThemeBackground;
+ DrawThemeParentBackgroundProc *DrawThemeParentBackground;
+ DrawThemeEdgeProc *DrawThemeEdge;
+ DrawThemeTextProc *DrawThemeText;
+ GetThemePartSizeProc *GetThemePartSize;
+ GetThemeTextExtentProc *GetThemeTextExtent;
+ IsThemeActiveProc *IsThemeActive;
+
+ HWND stubWindow;
+} XPThemeProcs;
+
+typedef struct
+{
+ HINSTANCE hlibrary;
+ XPThemeProcs *procs;
+} XPThemeData;
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * LoadXPThemeProcs --
+ * Initialize XP theming support.
+ *
+ * XP theme support is included in UXTHEME.DLL
+ * We dynamically load this DLL at runtime instead of linking
+ * to it at build-time.
+ *
+ * Returns:
+ * A pointer to an XPThemeProcs table if successful, NULL otherwise.
+ */
+
+static XPThemeProcs *
+LoadXPThemeProcs(HINSTANCE *phlib)
+{
+ OSVERSIONINFO os;
+
+ /*
+ * We have to check whether we are running at least on Windows XP.
+ * In order to determine this we call GetVersionEx directly, although
+ * it would be a good idea to wrap it inside a function similar to
+ * TkWinGetPlatformId...
+ */
+ ZeroMemory(&os, sizeof(os));
+ os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&os);
+ if (os.dwMajorVersion >= 5 && os.dwMinorVersion >= 1) {
+ /*
+ * We are running under Windows XP or a newer version.
+ * Load the library "uxtheme.dll", where the native widget
+ * drawing routines are implemented.
+ */
+ HINSTANCE handle;
+ *phlib = handle = LoadLibrary("uxtheme.dll");
+ if (handle != 0)
+ {
+ /*
+ * We have successfully loaded the library. Proceed in storing the
+ * addresses of the functions we want to use.
+ */
+ XPThemeProcs *procs = (XPThemeProcs*)ckalloc(sizeof(XPThemeProcs));
+#define LOADPROC(name) \
+ (0 != (procs->name = (name ## Proc *)GetProcAddress(handle, #name) ))
+
+ if ( LOADPROC(OpenThemeData)
+ && LOADPROC(CloseThemeData)
+ && LOADPROC(DrawThemeBackground)
+ && LOADPROC(DrawThemeParentBackground)
+ && LOADPROC(DrawThemeEdge)
+ && LOADPROC(DrawThemeText)
+ && LOADPROC(GetThemePartSize)
+ && LOADPROC(GetThemeTextExtent)
+ && LOADPROC(IsThemeActive)
+ )
+ {
+ return procs;
+ }
+#undef LOADPROC
+ ckfree((char*)procs);
+ }
+ }
+ return 0;
+}
+
+/*
+ * XPThemeDeleteProc --
+ *
+ * Release any theme allocated resources.
+ */
+
+static void
+XPThemeDeleteProc(void *clientData)
+{
+ XPThemeData *themeData = clientData;
+ FreeLibrary(themeData->hlibrary);
+ ckfree(clientData);
+}
+
+static int
+XPThemeEnabled(Ttk_Theme theme, void *clientData)
+{
+ XPThemeData *themeData = clientData;
+ return themeData->procs->IsThemeActive();
+}
+
+/*
+ * BoxToRect --
+ * Helper routine. Returns a RECT data structure.
+ */
+static RECT
+BoxToRect(Ttk_Box b)
+{
+ RECT rc;
+ rc.top = b.y;
+ rc.left = b.x;
+ rc.bottom = b.y + b.height;
+ rc.right = b.x + b.width;
+ return rc;
+}
+
+/*
+ * Map Tk state bitmaps to XP style enumerated values.
+ */
+static Ttk_StateTable null_statemap[] = { {0,0,0} };
+
+/*
+ * Pushbuttons (Tk: "Button")
+ */
+static Ttk_StateTable pushbutton_statemap[] =
+{
+ { PBS_DISABLED, TTK_STATE_DISABLED, 0 },
+ { PBS_PRESSED, TTK_STATE_PRESSED, 0 },
+ { PBS_HOT, TTK_STATE_ACTIVE, 0 },
+ { PBS_DEFAULTED, TTK_STATE_ALTERNATE, 0 },
+ { PBS_NORMAL, 0, 0 }
+};
+
+/*
+ * Checkboxes (Tk: "Checkbutton")
+ *
+ * Missing: CBS_MIXEDDISABLED CBS_MIXEDHOT CBS_MIXEDNORMAL CBS_MIXEDPRESSED
+ */
+static Ttk_StateTable checkbox_statemap[] =
+{
+{CBS_CHECKEDDISABLED, TTK_STATE_DISABLED|TTK_STATE_SELECTED, 0},
+{CBS_CHECKEDPRESSED, TTK_STATE_PRESSED|TTK_STATE_SELECTED, 0},
+{CBS_CHECKEDHOT, TTK_STATE_ACTIVE|TTK_STATE_SELECTED, 0},
+{CBS_CHECKEDNORMAL, TTK_STATE_SELECTED, 0},
+{CBS_UNCHECKEDDISABLED, TTK_STATE_DISABLED, TTK_STATE_SELECTED},
+{CBS_UNCHECKEDPRESSED, TTK_STATE_PRESSED, TTK_STATE_SELECTED},
+{CBS_UNCHECKEDHOT, TTK_STATE_ACTIVE, TTK_STATE_SELECTED},
+{CBS_UNCHECKEDNORMAL, 0,0 }
+};
+
+/*
+ * Radiobuttons:
+ */
+static Ttk_StateTable radiobutton_statemap[] =
+{
+{RBS_CHECKEDDISABLED, TTK_STATE_DISABLED|TTK_STATE_SELECTED, 0},
+{RBS_CHECKEDPRESSED, TTK_STATE_PRESSED|TTK_STATE_SELECTED, 0},
+{RBS_CHECKEDHOT, TTK_STATE_ACTIVE|TTK_STATE_SELECTED, 0},
+{RBS_CHECKEDNORMAL, TTK_STATE_SELECTED, 0},
+{RBS_UNCHECKEDDISABLED, TTK_STATE_DISABLED, TTK_STATE_SELECTED},
+{RBS_UNCHECKEDPRESSED, TTK_STATE_PRESSED, TTK_STATE_SELECTED},
+{RBS_UNCHECKEDHOT, TTK_STATE_ACTIVE, TTK_STATE_SELECTED},
+{RBS_UNCHECKEDNORMAL, 0,0 }
+};
+
+/*
+ * Groupboxes (tk: "frame")
+ */
+static Ttk_StateTable groupbox_statemap[] =
+{
+{GBS_DISABLED, TTK_STATE_DISABLED, 0},
+{GBS_NORMAL, 0,0 }
+};
+
+/*
+ * Edit fields (tk: "entry")
+ */
+static Ttk_StateTable edittext_statemap[] =
+{
+ { ETS_DISABLED, TTK_STATE_DISABLED, 0 },
+ { ETS_READONLY, TTK_STATE_READONLY, 0 },
+ { ETS_FOCUSED, TTK_STATE_FOCUS, 0 },
+ { ETS_HOT, TTK_STATE_ACTIVE, 0 },
+ { ETS_NORMAL, 0, 0 }
+/* NOT USED: ETS_ASSIST, ETS_SELECTED */
+};
+
+/*
+ * Combobox text field statemap:
+ * Same as edittext_statemap, but doesn't use ETS_READONLY
+ * (fixes: #1032409)
+ */
+static Ttk_StateTable combotext_statemap[] =
+{
+ { ETS_DISABLED, TTK_STATE_DISABLED, 0 },
+ { ETS_FOCUSED, TTK_STATE_FOCUS, 0 },
+ { ETS_HOT, TTK_STATE_ACTIVE, 0 },
+ { ETS_NORMAL, 0, 0 }
+};
+
+/*
+ * Combobox button: (CBP_DROPDOWNBUTTON)
+ */
+static Ttk_StateTable combobox_statemap[] = {
+ { CBXS_DISABLED, TTK_STATE_DISABLED, 0 },
+ { CBXS_PRESSED, TTK_STATE_PRESSED, 0 },
+ { CBXS_HOT, TTK_STATE_ACTIVE, 0 },
+ { CBXS_NORMAL, 0, 0 }
+};
+
+/*
+ * Toolbar buttons (TP_BUTTON):
+ */
+static Ttk_StateTable toolbutton_statemap[] = {
+ { TS_DISABLED, TTK_STATE_DISABLED, 0 },
+ { TS_PRESSED, TTK_STATE_PRESSED, 0 },
+ { TS_HOTCHECKED, TTK_STATE_SELECTED|TTK_STATE_ACTIVE, 0 },
+ { TS_CHECKED, TTK_STATE_SELECTED, 0 },
+ { TS_HOT, TTK_STATE_ACTIVE, 0 },
+ { TS_NORMAL, 0,0 }
+};
+
+/*
+ * Scrollbars (Tk: "Scrollbar.thumb")
+ */
+static Ttk_StateTable scrollbar_statemap[] =
+{
+ { SCRBS_DISABLED, TTK_STATE_DISABLED, 0 },
+ { SCRBS_PRESSED, TTK_STATE_PRESSED, 0 },
+ { SCRBS_HOT, TTK_STATE_ACTIVE, 0 },
+ { SCRBS_NORMAL, 0, 0 }
+};
+
+static Ttk_StateTable uparrow_statemap[] =
+{
+ { ABS_UPDISABLED, TTK_STATE_DISABLED, 0 },
+ { ABS_UPPRESSED, TTK_STATE_PRESSED, 0 },
+ { ABS_UPHOT, TTK_STATE_ACTIVE, 0 },
+ { ABS_UPNORMAL, 0, 0 }
+};
+
+static Ttk_StateTable downarrow_statemap[] =
+{
+ { ABS_DOWNDISABLED, TTK_STATE_DISABLED, 0 },
+ { ABS_DOWNPRESSED, TTK_STATE_PRESSED, 0 },
+ { ABS_DOWNHOT, TTK_STATE_ACTIVE, 0 },
+ { ABS_DOWNNORMAL, 0, 0 }
+};
+
+static Ttk_StateTable leftarrow_statemap[] =
+{
+ { ABS_LEFTDISABLED, TTK_STATE_DISABLED, 0 },
+ { ABS_LEFTPRESSED, TTK_STATE_PRESSED, 0 },
+ { ABS_LEFTHOT, TTK_STATE_ACTIVE, 0 },
+ { ABS_LEFTNORMAL, 0, 0 }
+};
+
+static Ttk_StateTable rightarrow_statemap[] =
+{
+ { ABS_RIGHTDISABLED,TTK_STATE_DISABLED, 0 },
+ { ABS_RIGHTPRESSED, TTK_STATE_PRESSED, 0 },
+ { ABS_RIGHTHOT, TTK_STATE_ACTIVE, 0 },
+ { ABS_RIGHTNORMAL, 0, 0 }
+};
+
+/*
+ * Trackbar thumb: (Tk: "scale slider")
+ */
+static Ttk_StateTable scale_statemap[] =
+{
+ { TUS_DISABLED, TTK_STATE_DISABLED, 0 },
+ { TUS_PRESSED, TTK_STATE_PRESSED, 0 },
+ { TUS_FOCUSED, TTK_STATE_FOCUS, 0 },
+ { TUS_HOT, TTK_STATE_ACTIVE, 0 },
+ { TUS_NORMAL, 0, 0 }
+};
+
+static Ttk_StateTable tabitem_statemap[] =
+{
+ { TIS_DISABLED, TTK_STATE_DISABLED, 0 },
+ { TIS_SELECTED, TTK_STATE_SELECTED, 0 },
+ { TIS_HOT, TTK_STATE_ACTIVE, 0 },
+ { TIS_FOCUSED, TTK_STATE_FOCUS, 0 },
+ { TIS_NORMAL, 0, 0 },
+};
+
+
+/*
+ *----------------------------------------------------------------------
+ * +++ Element data:
+ *
+ * The following structure is passed as the 'clientData' pointer
+ * to most elements in this theme. It contains data relevant
+ * to a single XP Theme "part".
+ *
+ * <<NOTE-GetThemeMargins>>:
+ * In theory, we should be call GetThemeMargins(...TMT_CONTENTRECT...)
+ * to calculate the internal padding. In practice, this routine
+ * only seems to work properly for BP_PUSHBUTTON. So we hardcode
+ * the required padding at element registration time instead.
+ *
+ * <<NOTE-GetThemePartSize>>:
+ * This gives bogus metrics for some parts (in particular,
+ * BP_PUSHBUTTONS). Set the IGNORE_THEMESIZE flag to skip this call.
+ */
+
+typedef struct /* XP element specifications */
+{
+ const char *elementName; /* Tk theme engine element name */
+ Ttk_ElementSpec *elementSpec;
+ /* Element spec (usually GenericElementSpec) */
+ LPCWSTR className; /* Windows window class name */
+ int partId; /* BP_PUSHBUTTON, BP_CHECKBUTTON, etc. */
+ Ttk_StateTable *statemap; /* Map Tk states to XP states */
+ Ttk_Padding padding; /* See NOTE-GetThemeMargins */
+ int flags;
+# define IGNORE_THEMESIZE 0x1 /* See NOTE-GetThemePartSize */
+} ElementInfo;
+
+typedef struct
+{
+ /*
+ * Static data, initialized when element is registered:
+ */
+ ElementInfo *info;
+ XPThemeProcs *procs; /* Pointer to theme procedure table */
+
+ /*
+ * Dynamic data, allocated by InitElementData:
+ */
+ HTHEME hTheme;
+ HDC hDC;
+ HWND hwnd;
+
+ /* For TkWinDrawableReleaseDC: */
+ Drawable drawable;
+ TkWinDCState dcState;
+} ElementData;
+
+static ElementData *
+NewElementData(XPThemeProcs *procs, ElementInfo *info)
+{
+ ElementData *elementData = (ElementData*)ckalloc(sizeof(ElementData));
+
+ elementData->procs = procs;
+ elementData->info = info;
+ elementData->hTheme = elementData->hDC = 0;
+
+ return elementData;
+}
+
+static void DestroyElementData(void *elementData)
+{
+ ckfree(elementData);
+}
+
+/*
+ * InitElementData --
+ * Looks up theme handle. If Drawable argument is non-NULL,
+ * also initializes DC.
+ *
+ * Returns:
+ * 1 on success, 0 on error.
+ * Caller must later call FreeElementData() so this element
+ * can be reused.
+ */
+
+static int
+InitElementData(ElementData *elementData, Tk_Window tkwin, Drawable d)
+{
+ Window win = Tk_WindowId(tkwin);
+
+ if (win != None) {
+ elementData->hwnd = Tk_GetHWND(win);
+ } else {
+ elementData->hwnd = elementData->procs->stubWindow;
+ }
+
+ elementData->hTheme = elementData->procs->OpenThemeData(
+ elementData->hwnd, elementData->info->className);
+
+ if (!elementData->hTheme)
+ return 0;
+
+ elementData->drawable = d;
+ if (d != 0) {
+ elementData->hDC = TkWinGetDrawableDC(Tk_Display(tkwin), d,
+ &elementData->dcState);
+ }
+
+ return 1;
+}
+
+static void
+FreeElementData(ElementData *elementData)
+{
+ elementData->procs->CloseThemeData(elementData->hTheme);
+ if (elementData->drawable != 0) {
+ TkWinReleaseDrawableDC(
+ elementData->drawable, elementData->hDC, &elementData->dcState);
+ }
+}
+
+/*----------------------------------------------------------------------
+ * +++ Generic element implementation.
+ *
+ * Used for elements which are handled entirely by the XP Theme API,
+ * such as radiobutton and checkbutton indicators, scrollbar arrows, etc.
+ */
+
+static void
+GenericElementGeometry(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
+{
+ ElementData *elementData = clientData;
+ HRESULT result;
+ SIZE size;
+
+ if (!InitElementData(elementData, tkwin, 0))
+ return;
+
+ if (!(elementData->info->flags & IGNORE_THEMESIZE)) {
+ result = elementData->procs->GetThemePartSize(
+ elementData->hTheme,
+ elementData->hDC,
+ elementData->info->partId,
+ Ttk_StateTableLookup(elementData->info->statemap, 0),
+ NULL /*RECT *prc*/,
+ TS_TRUE,
+ &size);
+
+ if (SUCCEEDED(result)) {
+ *widthPtr = size.cx;
+ *heightPtr = size.cy;
+ }
+ }
+
+ /* See NOTE-GetThemeMargins
+ */
+ *paddingPtr = elementData->info->padding;
+}
+
+static void
+GenericElementDraw(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, unsigned int state)
+{
+ ElementData *elementData = clientData;
+ RECT rc = BoxToRect(b);
+
+ if (!InitElementData(elementData, tkwin, d))
+ return;
+
+ elementData->procs->DrawThemeBackground(
+ elementData->hTheme,
+ elementData->hDC,
+ elementData->info->partId,
+ Ttk_StateTableLookup(elementData->info->statemap, state),
+ &rc,
+ NULL/*pContentRect*/);
+
+ FreeElementData(elementData);
+}
+
+static Ttk_ElementSpec GenericElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(NullElement),
+ NullElementOptions,
+ GenericElementGeometry,
+ GenericElementDraw
+};
+
+/*----------------------------------------------------------------------
+ * +++ Scrollbar thumb element.
+ * Same as a GenericElement, but don't draw in the disabled state.
+ */
+
+static void
+ThumbElementDraw(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, unsigned int state)
+{
+ ElementData *elementData = clientData;
+ unsigned stateId = Ttk_StateTableLookup(elementData->info->statemap, state);
+ RECT rc = BoxToRect(b);
+
+ /*
+ * Don't draw the thumb if we are disabled.
+ */
+ if (state & TTK_STATE_DISABLED)
+ return;
+
+ if (!InitElementData(elementData, tkwin, d))
+ return;
+
+ elementData->procs->DrawThemeBackground(elementData->hTheme,
+ elementData->hDC, elementData->info->partId, stateId,
+ &rc, NULL);
+
+ FreeElementData(elementData);
+}
+
+static Ttk_ElementSpec ThumbElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(NullElement),
+ NullElementOptions,
+ GenericElementGeometry,
+ ThumbElementDraw
+};
+
+/*----------------------------------------------------------------------
+ * +++ Progress bar element.
+ * Increases the requested length of PP_CHUNK and PP_CHUNKVERT parts
+ * so that indeterminate progress bars show 3 bars instead of 1.
+ */
+
+static void PbarElementGeometry(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
+{
+ ElementData *elementData = clientData;
+ int nBars = 3;
+
+ GenericElementGeometry(clientData, elementRecord, tkwin,
+ widthPtr, heightPtr, paddingPtr);
+
+ if (elementData->info->partId == PP_CHUNK) {
+ *widthPtr *= nBars;
+ } else if (elementData->info->partId == PP_CHUNKVERT) {
+ *heightPtr *= nBars;
+ }
+}
+
+static Ttk_ElementSpec PbarElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(NullElement),
+ NullElementOptions,
+ PbarElementGeometry,
+ GenericElementDraw
+};
+
+/*----------------------------------------------------------------------
+ * +++ Notebook tab element.
+ * Same as generic element, with additional logic to select
+ * proper iPartID for the leftmost tab.
+ *
+ * Notes: TABP_TABITEMRIGHTEDGE (or TABP_TOPTABITEMRIGHTEDGE,
+ * which appears to be identical) should be used if the
+ * tab is exactly at the right edge of the notebook, but
+ * not if it's simply the rightmost tab. This information
+ * is not available.
+ *
+ * The TIS_* and TTKS_* definitions are identical, so
+ * we can use the same statemap no matter what the partId.
+ */
+static void TabElementDraw(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, unsigned int state)
+{
+ ElementData *elementData = clientData;
+ int partId = elementData->info->partId;
+ RECT rc = BoxToRect(b);
+
+ if (!InitElementData(elementData, tkwin, d))
+ return;
+ if (state & TTK_STATE_USER1)
+ partId = TABP_TABITEMLEFTEDGE;
+ elementData->procs->DrawThemeBackground(
+ elementData->hTheme, elementData->hDC, partId,
+ Ttk_StateTableLookup(elementData->info->statemap, state), &rc, NULL);
+ FreeElementData(elementData);
+}
+
+static Ttk_ElementSpec TabElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(NullElement),
+ NullElementOptions,
+ GenericElementGeometry,
+ TabElementDraw
+};
+
+/*----------------------------------------------------------------------
+ * +++ Tree indicator element.
+ *
+ * Generic element, but don't display at all if TTK_STATE_LEAF (=USER2) set
+ */
+
+#define TTK_STATE_OPEN TTK_STATE_USER1
+#define TTK_STATE_LEAF TTK_STATE_USER2
+
+static Ttk_StateTable header_statemap[] =
+{
+ { HIS_PRESSED, TTK_STATE_PRESSED, 0 },
+ { HIS_HOT, TTK_STATE_ACTIVE, 0 },
+ { HIS_NORMAL, 0,0 },
+};
+
+static Ttk_StateTable tvpglyph_statemap[] =
+{
+ { GLPS_OPENED, TTK_STATE_OPEN, 0 },
+ { GLPS_CLOSED, 0,0 },
+};
+
+static void TreeIndicatorElementDraw(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, unsigned int state)
+{
+ if (!(state & TTK_STATE_LEAF)) {
+ GenericElementDraw(clientData,elementRecord,tkwin,d,b,state);
+ }
+}
+
+static Ttk_ElementSpec TreeIndicatorElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(NullElement),
+ NullElementOptions,
+ GenericElementGeometry,
+ TreeIndicatorElementDraw
+};
+
+#if BROKEN_TEXT_ELEMENT
+
+/*
+ *----------------------------------------------------------------------
+ * Text element (does not work yet).
+ *
+ * According to "Using Windows XP Visual Styles", we need to select
+ * a font into the DC before calling DrawThemeText().
+ * There's just no easy way to get an HFONT out of a Tk_Font.
+ * Maybe GetThemeFont() would work?
+ *
+ */
+
+typedef struct
+{
+ Tcl_Obj *textObj;
+ Tcl_Obj *fontObj;
+} TextElement;
+
+static Ttk_ElementOptionSpec TextElementOptions[] =
+{
+ { "-text", TK_OPTION_STRING,
+ Tk_Offset(TextElement,textObj), "" },
+ { "-font", TK_OPTION_FONT,
+ Tk_Offset(TextElement,fontObj), DEFAULT_FONT },
+ { NULL }
+};
+
+static void
+TextElementGeometry(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
+{
+ TextElement *element = elementRecord;
+ ElementData *elementData = clientData;
+ RECT rc = {0, 0};
+ HRESULT hr = S_OK;
+
+ if (!InitElementData(elementData, tkwin, 0))
+ return;
+
+ hr = elementData->procs->GetThemeTextExtent(
+ elementData->hTheme,
+ elementData->hDC,
+ elementData->info->partId,
+ Ttk_StateTableLookup(elementData->info->statemap, 0),
+ Tcl_GetUnicode(element->textObj),
+ -1,
+ DT_LEFT,// | DT_BOTTOM | DT_NOPREFIX,
+ NULL,
+ &rc);
+
+ if (SUCCEEDED(hr)) {
+ *widthPtr = rc.right - rc.left;
+ *heightPtr = rc.bottom - rc.top;
+ }
+ if (*widthPtr < 80) *widthPtr = 80;
+ if (*heightPtr < 20) *heightPtr = 20;
+
+ FreeElementData(elementData);
+}
+
+static void
+TextElementDraw(
+ ClientData clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, unsigned int state)
+{
+ TextElement *element = elementRecord;
+ ElementData *elementData = clientData;
+ RECT rc = BoxToRect(b);
+ HRESULT hr = S_OK;
+
+ if (!InitElementData(elementData, tkwin, d))
+ return;
+
+ hr = elementData->procs->DrawThemeText(
+ elementData->hTheme,
+ elementData->hDC,
+ elementData->info->partId,
+ Ttk_StateTableLookup(elementData->info->statemap, state),
+ Tcl_GetUnicode(element->textObj),
+ -1,
+ DT_LEFT,// | DT_BOTTOM | DT_NOPREFIX,
+ (state & TTK_STATE_DISABLED) ? DTT_GRAYED : 0,
+ &rc);
+ FreeElementData(elementData);
+}
+
+static Ttk_ElementSpec TextElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(TextElement),
+ TextElementOptions,
+ TextElementGeometry,
+ TextElementDraw
+};
+
+#endif /* BROKEN_TEXT_ELEMENT */
+
+/*----------------------------------------------------------------------
+ * +++ Widget layouts:
+ */
+
+TTK_BEGIN_LAYOUT(ButtonLayout)
+ TTK_GROUP("Button.button", TTK_FILL_BOTH,
+ TTK_GROUP("Button.focus", TTK_FILL_BOTH,
+ TTK_GROUP("Button.padding", TTK_FILL_BOTH,
+ TTK_NODE("Button.label", TTK_FILL_BOTH))))
+TTK_END_LAYOUT
+
+TTK_BEGIN_LAYOUT(MenubuttonLayout)
+ TTK_NODE("Menubutton.dropdown", TTK_PACK_RIGHT|TTK_FILL_Y)
+ TTK_GROUP("Menubutton.button", TTK_PACK_RIGHT|TTK_EXPAND|TTK_FILL_BOTH,
+ TTK_GROUP("Menubutton.padding", TTK_PACK_LEFT|TTK_EXPAND|TTK_FILL_X,
+ TTK_NODE("Menubutton.label", 0)))
+TTK_END_LAYOUT
+
+TTK_BEGIN_LAYOUT(HorizontalScrollbarLayout)
+ TTK_GROUP("Horizontal.Scrollbar.trough", TTK_FILL_X,
+ TTK_NODE("Horizontal.Scrollbar.leftarrow", TTK_PACK_LEFT)
+ TTK_NODE("Horizontal.Scrollbar.rightarrow", TTK_PACK_RIGHT)
+ TTK_GROUP("Horizontal.Scrollbar.thumb", TTK_FILL_BOTH|TTK_UNIT,
+ TTK_NODE("Horizontal.Scrollbar.grip", 0)))
+TTK_END_LAYOUT
+
+TTK_BEGIN_LAYOUT(VerticalScrollbarLayout)
+ TTK_GROUP("Vertical.Scrollbar.trough", TTK_FILL_Y,
+ TTK_NODE("Vertical.Scrollbar.uparrow", TTK_PACK_TOP)
+ TTK_NODE("Vertical.Scrollbar.downarrow", TTK_PACK_BOTTOM)
+ TTK_GROUP("Vertical.Scrollbar.thumb", TTK_FILL_BOTH|TTK_UNIT,
+ TTK_NODE("Vertical.Scrollbar.grip", 0)))
+TTK_END_LAYOUT
+
+TTK_BEGIN_LAYOUT(VerticalScaleLayout)
+ TTK_GROUP("Scale.focus", TTK_EXPAND|TTK_FILL_BOTH,
+ TTK_GROUP("Vertical.Scale.trough", TTK_EXPAND|TTK_FILL_BOTH,
+ TTK_NODE("Vertical.Scale.track", TTK_FILL_Y)
+ TTK_NODE("Vertical.Scale.slider", TTK_PACK_TOP) ))
+TTK_END_LAYOUT
+
+TTK_BEGIN_LAYOUT(HorizontalScaleLayout)
+ TTK_GROUP("Scale.focus", TTK_EXPAND|TTK_FILL_BOTH,
+ TTK_GROUP("Horizontal.Scale.trough", TTK_EXPAND|TTK_FILL_BOTH,
+ TTK_NODE("Horizontal.Scale.track", TTK_FILL_X)
+ TTK_NODE("Horizontal.Scale.slider", TTK_PACK_LEFT) ))
+TTK_END_LAYOUT
+
+/*----------------------------------------------------------------------
+ * +++ XP element info table:
+ */
+
+#define PAD(l,t,r,b) {l,t,r,b}
+#define NOPAD {0,0,0,0}
+
+/* name spec className partId statemap padding flags */
+
+static ElementInfo ElementInfoTable[] = {
+ { "Checkbutton.indicator", &GenericElementSpec, L"BUTTON",
+ BP_CHECKBOX, checkbox_statemap, PAD(0, 0, 4, 0), 0 },
+ { "Radiobutton.indicator", &GenericElementSpec, L"BUTTON",
+ BP_RADIOBUTTON, radiobutton_statemap, PAD(0, 0, 4, 0), 0 },
+ { "Button.button", &GenericElementSpec, L"BUTTON",
+ BP_PUSHBUTTON, pushbutton_statemap, PAD(3, 3, 3, 3), IGNORE_THEMESIZE },
+ { "Labelframe.border", &GenericElementSpec, L"BUTTON",
+ BP_GROUPBOX, groupbox_statemap, PAD(2, 2, 2, 2), 0 },
+ { "Entry.field", &GenericElementSpec, L"EDIT", EP_EDITTEXT,
+ edittext_statemap, PAD(1, 1, 1, 1), 0 },
+ { "Combobox.field", &GenericElementSpec, L"EDIT",
+ EP_EDITTEXT, combotext_statemap, PAD(1, 1, 1, 1), 0 },
+ { "Combobox.downarrow", &GenericElementSpec, L"COMBOBOX",
+ CP_DROPDOWNBUTTON, combobox_statemap, NOPAD, 0 },
+ { "Vertical.Scrollbar.trough", &GenericElementSpec, L"SCROLLBAR",
+ SBP_UPPERTRACKVERT, scrollbar_statemap, NOPAD, 0 },
+ { "Vertical.Scrollbar.thumb", &ThumbElementSpec, L"SCROLLBAR",
+ SBP_THUMBBTNVERT, scrollbar_statemap, NOPAD, 0 },
+ { "Vertical.Scrollbar.grip", &GenericElementSpec, L"SCROLLBAR",
+ SBP_GRIPPERVERT, scrollbar_statemap, NOPAD, 0 },
+ { "Horizontal.Scrollbar.trough", &GenericElementSpec, L"SCROLLBAR",
+ SBP_UPPERTRACKHORZ, scrollbar_statemap, NOPAD, 0 },
+ { "Horizontal.Scrollbar.thumb", &ThumbElementSpec, L"SCROLLBAR",
+ SBP_THUMBBTNHORZ, scrollbar_statemap, NOPAD, 0 },
+ { "Horizontal.Scrollbar.grip", &GenericElementSpec, L"SCROLLBAR",
+ SBP_GRIPPERHORZ, scrollbar_statemap, NOPAD, 0 },
+ { "Scrollbar.uparrow", &GenericElementSpec, L"SCROLLBAR",
+ SBP_ARROWBTN, uparrow_statemap, NOPAD, 0 },
+ { "Scrollbar.downarrow", &GenericElementSpec, L"SCROLLBAR",
+ SBP_ARROWBTN, downarrow_statemap, NOPAD, 0 },
+ { "Scrollbar.leftarrow", &GenericElementSpec, L"SCROLLBAR",
+ SBP_ARROWBTN, leftarrow_statemap, NOPAD, 0 },
+ { "Scrollbar.rightarrow", &GenericElementSpec, L"SCROLLBAR",
+ SBP_ARROWBTN, rightarrow_statemap, NOPAD, 0 },
+ { "Horizontal.Scale.slider", &GenericElementSpec, L"TRACKBAR",
+ TKP_THUMB, scale_statemap, NOPAD, 0 },
+ { "Vertical.Scale.slider", &GenericElementSpec, L"TRACKBAR",
+ TKP_THUMBVERT, scale_statemap, NOPAD, 0 },
+ { "Horizontal.Scale.track", &GenericElementSpec, L"TRACKBAR",
+ TKP_TRACK, scale_statemap, NOPAD, 0 },
+ { "Vertical.Scale.track", &GenericElementSpec, L"TRACKBAR",
+ TKP_TRACKVERT, scale_statemap, NOPAD, 0 },
+ /* ttk::progressbar elements */
+ { "Horizontal.Progressbar.pbar", &PbarElementSpec, L"PROGRESS",
+ PP_CHUNK, null_statemap, NOPAD, 0 },
+ { "Vertical.Progressbar.pbar", &PbarElementSpec, L"PROGRESS",
+ PP_CHUNKVERT, null_statemap, NOPAD, 0 },
+ { "Horizontal.Progressbar.trough", &GenericElementSpec, L"PROGRESS",
+ PP_BAR, null_statemap, PAD(3,3,3,3), IGNORE_THEMESIZE },
+ { "Vertical.Progressbar.trough", &GenericElementSpec, L"PROGRESS",
+ PP_BARVERT, null_statemap, PAD(3,3,3,3), IGNORE_THEMESIZE },
+ /* ttk::notebook */
+ { "tab", &TabElementSpec, L"TAB",
+ TABP_TABITEM, tabitem_statemap, PAD(3,3,3,0), 0 },
+ { "client", &GenericElementSpec, L"TAB",
+ TABP_PANE, null_statemap, PAD(1,1,3,3), 0 },
+ { "NotebookPane.background", &GenericElementSpec, L"TAB",
+ TABP_BODY, null_statemap, NOPAD, 0 },
+ { "Toolbutton.border", &GenericElementSpec, L"TOOLBAR",
+ TP_BUTTON, toolbutton_statemap, NOPAD,0 },
+ { "Menubutton.button", &GenericElementSpec, L"TOOLBAR",
+ TP_SPLITBUTTON,toolbutton_statemap, NOPAD,0 },
+ { "Menubutton.dropdown", &GenericElementSpec, L"TOOLBAR",
+ TP_SPLITBUTTONDROPDOWN,toolbutton_statemap, NOPAD,0 },
+ { "Treeitem.indicator", &TreeIndicatorElementSpec, L"TREEVIEW",
+ TVP_GLYPH, tvpglyph_statemap, PAD(1,1,6,0), 0 },
+ { "Treeheading.border", &GenericElementSpec, L"HEADER",
+ HP_HEADERITEM, header_statemap, PAD(4,0,4,0),0 },
+ { "sizegrip", &GenericElementSpec, L"STATUS",
+ SP_GRIPPER, null_statemap, NOPAD,0 },
+
+#if BROKEN_TEXT_ELEMENT
+ { "Labelframe.text", &TextElementSpec, L"BUTTON",
+ BP_GROUPBOX, groupbox_statemap, NOPAD,0 },
+#endif
+
+ { 0,0,0,0,0,NOPAD,0 }
+};
+#undef PAD
+
+/*----------------------------------------------------------------------
+ * +++ Initialization routine:
+ */
+
+int XPTheme_Init(Tcl_Interp *interp, HWND hwnd)
+{
+ XPThemeData *themeData;
+ XPThemeProcs *procs;
+ HINSTANCE hlibrary;
+ Ttk_Theme themePtr, parentPtr;
+ ElementInfo *infoPtr;
+
+ procs = LoadXPThemeProcs(&hlibrary);
+ if (!procs)
+ return TCL_ERROR;
+ procs->stubWindow = hwnd;
+
+ /*
+ * Create the new style engine.
+ */
+ parentPtr = Ttk_GetTheme(interp, "winnative");
+ themePtr = Ttk_CreateTheme(interp, "xpnative", parentPtr);
+
+ if (!themePtr)
+ return TCL_ERROR;
+
+ /*
+ * Set theme data and cleanup proc
+ */
+
+ themeData = (XPThemeData *)ckalloc(sizeof(XPThemeData));
+ themeData->procs = procs;
+ themeData->hlibrary = hlibrary;
+
+ Ttk_SetThemeEnabledProc(themePtr, XPThemeEnabled, themeData);
+ Ttk_RegisterCleanup(interp, themeData, XPThemeDeleteProc);
+
+ /*
+ * New elements:
+ */
+ for (infoPtr = ElementInfoTable; infoPtr->elementName != 0; ++infoPtr) {
+ ClientData clientData = NewElementData(procs, infoPtr);
+ Ttk_RegisterElementSpec(
+ themePtr, infoPtr->elementName, infoPtr->elementSpec, clientData);
+ Ttk_RegisterCleanup(interp, clientData, DestroyElementData);
+ }
+
+ Ttk_RegisterElementSpec(themePtr, "Scale.trough", &NullElementSpec, 0);
+
+ /*
+ * Layouts:
+ */
+ Ttk_RegisterLayout(themePtr, "TButton", ButtonLayout);
+ Ttk_RegisterLayout(themePtr, "TMenubutton", MenubuttonLayout);
+ Ttk_RegisterLayout(themePtr, "Vertical.TScrollbar",
+ VerticalScrollbarLayout);
+ Ttk_RegisterLayout(themePtr, "Horizontal.TScrollbar",
+ HorizontalScrollbarLayout);
+ Ttk_RegisterLayout(themePtr, "Vertical.TScale", VerticalScaleLayout);
+ Ttk_RegisterLayout(themePtr, "Horizontal.TScale", HorizontalScaleLayout);
+
+ Tcl_PkgProvide(interp, "ttk::theme::xpnative", TTK_VERSION);
+
+ return TCL_OK;
+}
+
+#endif /* HAVE_UXTHEME_H */