From d6ae9ac6b68ade20d79d00780b721ba419701f0b Mon Sep 17 00:00:00 2001 From: patthoyts Date: Thu, 14 May 2009 00:53:04 +0000 Subject: Backported support for the Vista theme. This requires the vsapi element engine, the hover state and the theme script definition. --- ChangeLog | 15 +++ doc/ttk_image.n | 10 +- doc/ttk_style.n | 10 +- doc/ttk_vsapi.n | 97 +++++++++++++++++ doc/ttk_widget.n | 10 +- generic/ttk/ttkState.c | 9 +- generic/ttk/ttkTheme.h | 4 +- generic/ttk/ttkWidget.c | 12 ++- library/ttk/ttk.tcl | 16 +-- library/ttk/vistaTheme.tcl | 206 ++++++++++++++++++++++++++++++++++++ library/ttk/xpTheme.tcl | 13 +-- tests/ttk/vsapi.test | 48 +++++++++ win/ttkWinXPTheme.c | 257 +++++++++++++++++++++++++++++++++++++++------ 13 files changed, 641 insertions(+), 66 deletions(-) create mode 100644 doc/ttk_vsapi.n create mode 100644 library/ttk/vistaTheme.tcl create mode 100644 tests/ttk/vsapi.test diff --git a/ChangeLog b/ChangeLog index f7b29f4..28ff725 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2009-05-14 Pat Thoyts + + * doc/ttk_image.n: Backported support for the Vista theme. + * doc/ttk_style.n: This requires the vsapi element engine, + * doc/ttk_vsapi.n: the hover state and the theme script + * doc/ttk_widget.n: definition. + * generic/ttk/ttkState.c: + * generic/ttk/ttkTheme.h: + * generic/ttk/ttkWidget.c: + * library/ttk/ttk.tcl: + * library/ttk/vistaTheme.tcl: + * library/ttk/xpTheme.tcl: + * tests/ttk/vsapi.test: + * win/ttkWinXPTheme.c: + 2009-05-13 Pat Thoyts * generic/tkFont.c: [Bug 2791352]: backported fix and tests for diff --git a/doc/ttk_image.n b/doc/ttk_image.n index a84247a..0c38e94 100644 --- a/doc/ttk_image.n +++ b/doc/ttk_image.n @@ -4,13 +4,13 @@ '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: ttk_image.n,v 1.12 2007/12/13 15:23:44 dgp Exp $ +'\" RCS: @(#) $Id: ttk_image.n,v 1.12.2.1 2009/05/14 00:53:04 patthoyts Exp $ '\" .so man.macros -.TH ttk::image n 8.5 Tk "Tk Themed Widget" +.TH ttk_image n 8.5 Tk "Tk Themed Widget" .BS .SH NAME -ttk::image \- Define an element based on an image +ttk_image \- Define an element based on an image .SH SYNOPSIS \fBttk::style element create \fIname\fR \fBimage\fR \fIimageSpec\fR ?\fIoptions\fR? .BE @@ -72,6 +72,6 @@ style element create Button.button image \e \-border {2 4} \-sticky we .CE .SH "SEE ALSO" -image(n), photo(n) +ttk::intro(n), ttk::style(n), ttk_vsapi(n), image(n), photo(n) .SH KEYWORDS -pixmap theme, image +style, theme, appearance, pixmap theme, image diff --git a/doc/ttk_style.n b/doc/ttk_style.n index dcc74ad..b5d4121 100644 --- a/doc/ttk_style.n +++ b/doc/ttk_style.n @@ -4,7 +4,7 @@ '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: ttk_style.n,v 1.13 2008/03/16 22:37:45 dkf Exp $ +'\" RCS: @(#) $Id: ttk_style.n,v 1.13.2.1 2009/05/14 00:53:04 patthoyts Exp $ '\" .so man.macros .TH ttk::style n 8.5 Tk "Tk Themed Widget" @@ -58,9 +58,11 @@ for style \fIstyle\fR. .TP \fBttk::style element create\fR \fIelementName\fR \fItype\fR ?\fIargs...\fR? Creates a new element in the current theme of type \fItype\fR. -The only built-in element type is \fIimage\fR (see \fBttk_image\fR(n)), -although themes may define other element types -(see \fBTtk_RegisterElementFactory\fR). +The only cross-platform built-in element type is \fIimage\fR +(see \fBttk_image\fR(n)) but themes may define other element types +(see \fBTtk_RegisterElementFactory\fR). On suitable versions of Windows +an element factory is registered to create Windows theme elements +(see \fBttk_vsapi\fR(n)). .TP \fBttk::style element names\fR Returns the list of elements defined in the current theme. diff --git a/doc/ttk_vsapi.n b/doc/ttk_vsapi.n new file mode 100644 index 0000000..ef510dc --- /dev/null +++ b/doc/ttk_vsapi.n @@ -0,0 +1,97 @@ +'\" -*- 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.4.2.2 2009/05/14 00:53:04 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 padding quantities respectively. +This option may not be mixed with any other options. +.TP +\fB\-margins\fR \fIpadding\fR +Specifies the elements exterior padding. +\fIpadding\fR is a list of up to four integers specifying +the left, top, right and bottom padding quantities respectively. +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 or the part. 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. Unfortunately all the Visual Styles parts have +different state values and these must be looked up either in the +Microsoft documentation or more likely in the header files. The +original header to use was \fItmschema.h\fR but in more recent +versions of the Windows Development Kit this is \fIvssym32.h\fR. +.PP +If no \fIstateMap\fR parameter is given there is an implicit default +map of {{} 1} +.SH "EXAMPLE" +Create a correctly themed close button by changing the layout of +a \fBttk::button\fR(n). This uses the WINDOW part WP_SMALLCLOSEBUTTON +and as documented the states CBS_DISABLED, CBS_HOT, CBS_NORMAL and +CBS_PUSHED are mapped from ttk states. +.CS +ttk::style element create smallclose vsapi WINDOW 19 \\ + {disabled 4 pressed 3 active 2 {} 1} +ttk::style layout CloseButton {CloseButton.smallclose -sticky news} +pack [ttk::button .close -style CloseButton] +.CE +.PP +Change the appearence of a \fBttk::checkbutton\fR(n) to use the +Explorer pin part EBP_HEADERPIN. +.CS +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/doc/ttk_widget.n b/doc/ttk_widget.n index 7e99409..8b19f62 100644 --- a/doc/ttk_widget.n +++ b/doc/ttk_widget.n @@ -4,7 +4,7 @@ '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: ttk_widget.n,v 1.13.2.1 2008/05/11 00:31:03 patthoyts Exp $ +'\" RCS: @(#) $Id: ttk_widget.n,v 1.13.2.2 2009/05/14 00:53:04 patthoyts Exp $ '\" .so man.macros .TH ttk::widget n 8.5 Tk "Tk Themed Widget" @@ -230,6 +230,14 @@ state, and for buttons with \fB\-default active\fR. The widget's value is invalid. (Potential uses: scale widget value out of bounds, entry widget value failed validation.) +.TP +\fBhover\fR +The mouse cursor is within the widget. +This is similar to the \fBactive\fP state; +it is used in some themes for widgets that +provide distinct visual feedback for +the active widget in addition to the active element +within the widget. .PP A \fIstate specification\fR or \fIstateSpec\fR is a list of state names, optionally prefixed with an exclamation point (!) diff --git a/generic/ttk/ttkState.c b/generic/ttk/ttkState.c index 8923fa6..1c0db7d 100644 --- a/generic/ttk/ttkState.c +++ b/generic/ttk/ttkState.c @@ -1,5 +1,5 @@ /* - * $Id: ttkState.c,v 1.1 2006/10/31 01:42:26 hobbs Exp $ + * $Id: ttkState.c,v 1.1.4.1 2009/05/14 00:53:04 patthoyts Exp $ * * Tk widget state utilities. * @@ -27,6 +27,13 @@ static const char *stateNames[] = "alternate", /* Widget-specific alternate display style */ "invalid", /* Bad value */ "readonly", /* Editing/modification disabled */ + "hover", /* Mouse cursor is over widget */ + "reserved1", /* Reserved for future extension */ + "reserved2", /* Reserved for future extension */ + "reserved3", /* Reserved for future extension */ + "user3", /* User-definable state */ + "user2", /* User-definable state */ + "user1", /* User-definable state */ NULL }; diff --git a/generic/ttk/ttkTheme.h b/generic/ttk/ttkTheme.h index 5e7dc88..6d95c01 100644 --- a/generic/ttk/ttkTheme.h +++ b/generic/ttk/ttkTheme.h @@ -1,4 +1,4 @@ -/* $Id: ttkTheme.h,v 1.13 2007/12/13 15:26:26 dgp Exp $ +/* $Id: ttkTheme.h,v 1.13.2.1 2009/05/14 00:53:04 patthoyts Exp $ * Copyright (c) 2003 Joe English. Freely redistributable. * * Declarations for Tk theme engine. @@ -48,7 +48,7 @@ typedef unsigned int Ttk_State; #define TTK_STATE_ALTERNATE (1<<6) #define TTK_STATE_INVALID (1<<7) #define TTK_STATE_READONLY (1<<8) -#define TTK_STATE_USER7 (1<<9) +#define TTK_STATE_HOVER (1<<9) #define TTK_STATE_USER6 (1<<10) #define TTK_STATE_USER5 (1<<11) #define TTK_STATE_USER4 (1<<12) diff --git a/generic/ttk/ttkWidget.c b/generic/ttk/ttkWidget.c index 5f05ab4..6bc085b 100644 --- a/generic/ttk/ttkWidget.c +++ b/generic/ttk/ttkWidget.c @@ -1,4 +1,4 @@ -/* $Id: ttkWidget.c,v 1.11.2.1 2008/12/22 18:34:55 jenglish Exp $ +/* $Id: ttkWidget.c,v 1.11.2.2 2009/05/14 00:53:04 patthoyts Exp $ * Copyright (c) 2003, Joe English * * Core widget utilities. @@ -241,6 +241,8 @@ static const unsigned CoreEventMask | FocusChangeMask | VirtualEventMask | ActivateMask + | EnterWindowMask + | LeaveWindowMask ; static void CoreEventProc(ClientData clientData, XEvent *eventPtr) @@ -309,6 +311,14 @@ static void CoreEventProc(ClientData clientData, XEvent *eventPtr) corePtr->state |= TTK_STATE_BACKGROUND; TtkRedisplayWidget(corePtr); break; + case LeaveNotify: + corePtr->state &= ~TTK_STATE_HOVER; + TtkRedisplayWidget(corePtr); + break; + case EnterNotify: + corePtr->state |= TTK_STATE_HOVER; + TtkRedisplayWidget(corePtr); + break; case VirtualEvent: if (!strcmp("ThemeChanged", ((XVirtualEvent *)(eventPtr))->name)) { (void)UpdateLayout(corePtr->interp, corePtr); diff --git a/library/ttk/ttk.tcl b/library/ttk/ttk.tcl index c4d0ff1..70e5121 100644 --- a/library/ttk/ttk.tcl +++ b/library/ttk/ttk.tcl @@ -1,5 +1,5 @@ # -# $Id: ttk.tcl,v 1.8 2007/12/13 15:27:08 dgp Exp $ +# $Id: ttk.tcl,v 1.8.2.1 2009/05/14 00:53:04 patthoyts Exp $ # # Ttk widget set initialization script. # @@ -123,16 +123,18 @@ proc ttk::LoadThemes {} { uplevel #0 [list source [file join $library defaults.tcl]] set builtinThemes [style theme names] - foreach {theme script} { + foreach {theme scripts} { classic classicTheme.tcl alt altTheme.tcl clam clamTheme.tcl winnative winTheme.tcl - xpnative xpTheme.tcl + xpnative {xpTheme.tcl vistaTheme.tcl} aqua aquaTheme.tcl } { if {[lsearch -exact $builtinThemes $theme] >= 0} { - uplevel #0 [list source [file join $library $script]] + foreach script $scripts { + uplevel #0 [list source [file join $library $script]] + } } } } @@ -150,17 +152,17 @@ ttk::LoadThemes; rename ::ttk::LoadThemes {} # proc ttk::DefaultTheme {} { - set preferred [list aqua xpnative winnative] + set preferred [list aqua vista xpnative winnative] set userTheme [option get . tkTheme TkTheme] - if {$userTheme != {} && ![catch { + if {$userTheme ne {} && ![catch { uplevel #0 [list package require ttk::theme::$userTheme] }]} { return $userTheme } foreach theme $preferred { - if {[package provide ttk::theme::$theme] != ""} { + if {[package provide ttk::theme::$theme] ne ""} { return $theme } } diff --git a/library/ttk/vistaTheme.tcl b/library/ttk/vistaTheme.tcl new file mode 100644 index 0000000..76f3e3e --- /dev/null +++ b/library/ttk/vistaTheme.tcl @@ -0,0 +1,206 @@ +# +# Settings for Microsoft Windows Vista and Server 2008 +# + +# The Vista theme can only be defined on Windows Vista and above. The theme +# is created in C due to the need to assign a theme-enabled function for +# detecting when themeing is disabled. On systems that cannot support the +# Vista theme, there will be no such theme created and we must not +# evaluate this script. + +if {"vista" ni [ttk::style theme names]} { + return +} + +namespace eval ttk::theme::vista { + + ttk::style theme settings vista { + + ttk::style configure . \ + -background SystemButtonFace \ + -foreground SystemWindowText \ + -selectforeground SystemHighlightText \ + -selectbackground SystemHighlight \ + -font TkDefaultFont \ + ; + + ttk::style map "." \ + -foreground [list disabled SystemGrayText] \ + ; + + ttk::style configure TButton -anchor center -padding {1 1} -width -11 + ttk::style configure TRadiobutton -padding 2 + ttk::style configure TCheckbutton -padding 2 + ttk::style configure TMenubutton -padding {8 4} + + ttk::style configure TNotebook -tabmargins {2 2 2 0} + ttk::style map TNotebook.Tab \ + -expand [list selected {2 2 2 2}] + + # Treeview: + ttk::style configure Heading -font TkHeadingFont + ttk::style configure Treeview -background SystemWindow + ttk::style map Treeview \ + -background [list selected SystemHighlight] \ + -foreground [list selected SystemHighlightText] ; + + # Label and Toolbutton + ttk::style configure TLabelframe.Label -foreground "#0046d5" + + ttk::style configure Toolbutton -padding {4 4} + + # Combobox + ttk::style configure TCombobox -padding 2 + ttk::style element create Combobox.field vsapi \ + COMBOBOX 2 {{} 1} + ttk::style element create Combobox.border vsapi \ + COMBOBOX 4 {disabled 4 focus 3 active 2 hover 2 {} 1} + ttk::style element create Combobox.rightdownarrow vsapi \ + COMBOBOX 6 {disabled 4 pressed 3 active 2 {} 1} + ttk::style layout TCombobox { + Combobox.border -sticky nswe -border 0 -children { + Combobox.rightdownarrow -side right -sticky ns + Combobox.padding -expand 1 -sticky nswe -children { + Combobox.focus -expand 1 -sticky nswe -children { + Combobox.textarea -sticky nswe + } + } + } + } + # Vista.Combobox droplist frame + ttk::style element create ComboboxPopdownFrame.background vsapi\ + LISTBOX 3 {disabled 4 active 3 focus 2 {} 1} + ttk::style layout ComboboxPopdownFrame { + ComboboxPopdownFrame.background -sticky news -border 1 -children { + ComboboxPopdownFrame.padding -sticky news + } + } + ttk::style map TCombobox \ + -selectbackground [list !focus SystemWindow] \ + -selectforeground [list !focus SystemWindowText] \ + -foreground [list {readonly focus} SystemHighlightText] \ + -focusfill [list {readonly focus} SystemHighlight] \ + ; + + # Entry + ttk::style configure TEntry -padding {1 1 1 1} ;# Needs lookup + ttk::style element create Entry.field vsapi \ + EDIT 6 {disabled 4 focus 3 hover 2 {} 1} -padding {2 2 2 2} + ttk::style element create Entry.background vsapi \ + EDIT 3 {disabled 3 readonly 3 focus 4 hover 2 {} 1} + ttk::style layout TEntry { + Entry.field -sticky news -border 0 -children { + Entry.background -sticky news -children { + Entry.padding -sticky news -children { + Entry.textarea -sticky news + } + } + } + } + ttk::style map TEntry \ + -selectbackground [list !focus SystemWindow] \ + -selectforeground [list !focus SystemWindowText] \ + ; + + # Spinbox + ttk::style configure TSpinbox -padding 0 ;#{2 0 15 1} + ttk::style element create Spinbox.field vsapi \ + EDIT 9 {disabled 4 focus 3 hover 2 {} 1} -padding {1 1 1 2} + ttk::style element create Spinbox.background vsapi \ + EDIT 3 {disabled 3 readonly 3 focus 4 hover 2 {} 1} + ttk::style element create Spinbox.innerbg vsapi \ + EDIT 3 {disabled 3 readonly 3 focus 4 hover 2 {} 1}\ + -padding {2 0 15 1} + ttk::style element create Spinbox.uparrow vsapi \ + SPIN 1 {disabled 4 pressed 3 active 2 {} 1} \ + -height 5 -width 8 + ttk::style element create Spinbox.downarrow vsapi \ + SPIN 2 {disabled 4 pressed 3 active 2 {} 1} \ + -height 5 -width 8 + ttk::style layout TSpinbox { + Spinbox.field -sticky nswe -children { + Spinbox.background -sticky news -children { + Spinbox.padding -sticky news -children { + Spinbox.innerbg -sticky news -children { + Spinbox.textarea -expand 1 -sticky {} + } + } + Spinbox.uparrow -side top -sticky ens + Spinbox.downarrow -side bottom -sticky ens + } + } + } + ttk::style map TSpinbox \ + -selectbackground [list !focus SystemWindow] \ + -selectforeground [list !focus SystemWindowText] \ + ; + + + # SCROLLBAR elements (Vista includes a state for 'hover') + ttk::style element create Vertical.Scrollbar.uparrow vsapi \ + SCROLLBAR 1 {disabled 4 pressed 3 active 2 hover 17 {} 1} + ttk::style element create Vertical.Scrollbar.downarrow vsapi \ + SCROLLBAR 1 {disabled 8 pressed 7 active 6 hover 18 {} 5} + ttk::style element create Vertical.Scrollbar.trough vsapi \ + SCROLLBAR 7 {disabled 4 pressed 3 active 2 hover 5 {} 1} + ttk::style element create Vertical.Scrollbar.thumb vsapi \ + SCROLLBAR 3 {disabled 4 pressed 3 active 2 hover 5 {} 1} + ttk::style element create Vertical.Scrollbar.grip vsapi \ + SCROLLBAR 9 {disabled 4 pressed 3 active 2 hover 5 {} 1} + ttk::style element create Horizontal.Scrollbar.leftarrow vsapi \ + SCROLLBAR 1 {disabled 12 pressed 11 active 10 hover 19 {} 9} + ttk::style element create Horizontal.Scrollbar.rightarrow vsapi \ + SCROLLBAR 1 {disabled 16 pressed 15 active 14 hover 20 {} 13} + ttk::style element create Horizontal.Scrollbar.trough vsapi \ + SCROLLBAR 5 {disabled 4 pressed 3 active 2 hover 5 {} 1} + ttk::style element create Horizontal.Scrollbar.thumb vsapi \ + SCROLLBAR 2 {disabled 4 pressed 3 active 2 hover 5 {} 1} + ttk::style element create Horizontal.Scrollbar.grip vsapi \ + SCROLLBAR 8 {disabled 4 pressed 3 active 2 hover 5 {} 1} + + # Progressbar + ttk::style element create Horizontal.Progressbar.pbar vsapi \ + PROGRESS 3 {{} 1} -padding 8 + ttk::style layout Horizontal.TProgressbar { + Horizontal.Progressbar.trough -sticky nswe -children { + Horizontal.Progressbar.pbar -side left -sticky ns + } + } + ttk::style element create Vertical.Progressbar.pbar vsapi \ + PROGRESS 3 {{} 1} -padding 8 + ttk::style layout Vertical.TProgressbar { + Vertical.Progressbar.trough -sticky nswe -children { + Vertical.Progressbar.pbar -side bottom -sticky we + } + } + + # Scale + ttk::style element create Horizontal.Scale.slider vsapi \ + TRACKBAR 3 {disabled 5 focus 4 pressed 3 active 2 {} 1} \ + -width 6 -height 12 + ttk::style layout Horizontal.TScale { + Scale.focus -expand 1 -sticky nswe -children { + Horizontal.Scale.trough -expand 1 -sticky nswe -children { + Horizontal.Scale.track -sticky we + Horizontal.Scale.slider -side left -sticky {} + } + } + } + ttk::style element create Vertical.Scale.slider vsapi \ + TRACKBAR 6 {disabled 5 focus 4 pressed 3 active 2 {} 1} \ + -width 12 -height 6 + ttk::style layout Vertical.TScale { + Scale.focus -expand 1 -sticky nswe -children { + Vertical.Scale.trough -expand 1 -sticky nswe -children { + Vertical.Scale.track -sticky ns + Vertical.Scale.slider -side top -sticky {} + } + } + } + + # Treeview + ttk::style configure Item -padding {4 0 0 0} + + package provide ttk::theme::vista 1.0 + } +} \ No newline at end of file diff --git a/library/ttk/xpTheme.tcl b/library/ttk/xpTheme.tcl index a75864c..9b1c697 100644 --- a/library/ttk/xpTheme.tcl +++ b/library/ttk/xpTheme.tcl @@ -1,5 +1,5 @@ # -# $Id: xpTheme.tcl,v 1.6.2.1 2008/04/03 11:48:00 patthoyts Exp $ +# $Id: xpTheme.tcl,v 1.6.2.2 2009/05/14 00:53:04 patthoyts Exp $ # # Settings for 'xpnative' theme # @@ -31,15 +31,8 @@ namespace eval ttk::theme::xpnative { # Treeview: ttk::style configure Heading -font TkHeadingFont - ttk::style configure Row -background SystemWindow - ttk::style configure Cell -background SystemWindow - ttk::style map Row \ - -background [list selected SystemHighlight] \ - -foreground [list selected SystemHighlightText] ; - ttk::style map Cell \ - -background [list selected SystemHighlight] \ - -foreground [list selected SystemHighlightText] ; - ttk::style map Item \ + ttk::style configure Treeview -background SystemWindow + ttk::style map Treeview \ -background [list selected SystemHighlight] \ -foreground [list selected SystemHighlightText] ; diff --git a/tests/ttk/vsapi.test b/tests/ttk/vsapi.test new file mode 100644 index 0000000..7000e3e --- /dev/null +++ b/tests/ttk/vsapi.test @@ -0,0 +1,48 @@ +# -*- tcl -*- +# $Id: vsapi.test,v 1.1.2.2 2009/05/14 00:53:04 patthoyts Exp $ +# + +package require Tk 8.5 +package require tcltest ; namespace import -force tcltest::* +loadTestedCommands + +testConstraint xpnative \ + [expr {[lsearch -exact [ttk::style theme names] xpnative] != -1}] + +test vsapi-1.1 "WINDOW WP_SMALLCLOSEBUTTON" -constraints {xpnative} -body { + ttk::style element create smallclose vsapi \ + WINDOW 19 {disabled 4 pressed 3 active 2 {} 1} + ttk::style layout CloseButton {CloseButton.smallclose -sticky news} + ttk::button .b -style CloseButton + pack .b -expand true -fill both + list [winfo reqwidth .b] [winfo reqheight .b] +} -cleanup { destroy .b } -result [list 13 13] + +test vsapi-1.2 "EXPLORERBAR EBP_HEADERPIN" -constraints {xpnative} -body { + 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} + ttk::checkbutton .pin -style Explorer.Pin + pack .pin -expand true -fill both + list [winfo reqwidth .pin] [winfo reqheight .pin] +} -cleanup { destroy .pin } -result [list 16 16] + +test vsapi-1.3 "EXPLORERBAR EBP_HEADERCLOSE" -constraints {xpnative} -body { + ttk::style element create headerclose vsapi \ + EXPLORERBAR 2 {pressed 3 active 2 {} 1} + ttk::style layout Explorer.CloseButton { + Explorer.CloseButton.headerclose -sticky news + } + ttk::button .b -style Explorer.CloseButton + pack .b -expand true -fill both + list [winfo reqwidth .b] [winfo reqheight .b] +} -cleanup { destroy .b } -result [list 16 16] + +tcltest::cleanupTests diff --git a/win/ttkWinXPTheme.c b/win/ttkWinXPTheme.c index 11a8269..0c5369c 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.18.2.1 2009/05/14 00:53:04 patthoyts Exp $ * * Tk theme engine which uses the Windows XP "Visual Styles" API * Adapted from Georgios Petasis' XP theme patch. @@ -43,15 +43,15 @@ typedef HRESULT (STDAPICALLTYPE GetThemePartSizeProc)(HTHEME,HDC, int iPartId, int iStateId, RECT *prc, enum THEMESIZE eSize, SIZE *psz); typedef int (STDAPICALLTYPE GetThemeSysSizeProc)(HTHEME,int); -/* GetThemeTextExtent and DrawThemeText only used with BROKEN_TEXT_ELEMENT */ +/* GetThemeTextExtent and DrawThemeText only used with BROKEN_TEXT_ELEMENT */ typedef HRESULT (STDAPICALLTYPE GetThemeTextExtentProc)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, const RECT *pBoundingRect, RECT *pExtent); typedef HRESULT (STDAPICALLTYPE DrawThemeTextProc)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect); -typedef BOOL (STDAPICALLTYPE IsThemeActiveProc)(VOID); -typedef BOOL (STDAPICALLTYPE IsAppThemedProc)(VOID); +typedef BOOL (STDAPICALLTYPE IsThemeActiveProc)(void); +typedef BOOL (STDAPICALLTYPE IsAppThemedProc)(void); typedef struct { @@ -93,7 +93,7 @@ LoadXPThemeProcs(HINSTANCE *phlib) { /* * Load the library "uxtheme.dll", where the native widget - * drawing routines are implemented. This will only succeed + * drawing routines are implemented. This will only succeed * if we are running at least on Windows XP. */ HINSTANCE handle; @@ -228,7 +228,7 @@ static Ttk_StateTable groupbox_statemap[] = /* * Edit fields (tk: "entry") */ -static Ttk_StateTable edittext_statemap[] = +static Ttk_StateTable edittext_statemap[] = { { ETS_DISABLED, TTK_STATE_DISABLED, 0 }, { ETS_READONLY, TTK_STATE_READONLY, 0 }, @@ -239,11 +239,11 @@ static Ttk_StateTable edittext_statemap[] = }; /* - * Combobox text field statemap: - * Same as edittext_statemap, but doesn't use ETS_READONLY + * Combobox text field statemap: + * Same as edittext_statemap, but doesn't use ETS_READONLY * (fixes: #1032409) */ -static Ttk_StateTable combotext_statemap[] = +static Ttk_StateTable combotext_statemap[] = { { ETS_DISABLED, TTK_STATE_DISABLED, 0 }, { ETS_FOCUSED, TTK_STATE_FOCUS, 0 }, @@ -258,6 +258,7 @@ static Ttk_StateTable combobox_statemap[] = { { CBXS_DISABLED, TTK_STATE_DISABLED, 0 }, { CBXS_PRESSED, TTK_STATE_PRESSED, 0 }, { CBXS_HOT, TTK_STATE_ACTIVE, 0 }, + { CBXS_HOT, TTK_STATE_HOVER, 0 }, { CBXS_NORMAL, 0, 0 } }; @@ -346,7 +347,7 @@ static Ttk_StateTable tabitem_statemap[] = * to most elements in this theme. It contains data relevant * to a single XP Theme "part". * - * <>: + * <>: * 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 @@ -355,7 +356,7 @@ static Ttk_StateTable tabitem_statemap[] = * The PAD_MARGINS flag bit determines whether the padding * should be added on the inside (0) or outside (1) of the element. * - * <>: + * <>: * This gives bogus metrics for some parts (in particular, * BP_PUSHBUTTONS). Set the IGNORE_THEMESIZE flag to skip this call. */ @@ -363,15 +364,16 @@ static Ttk_StateTable tabitem_statemap[] = typedef struct /* XP element specifications */ { const char *elementName; /* Tk theme engine element name */ - Ttk_ElementSpec *elementSpec; + 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; + 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 +408,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); } /* @@ -460,7 +474,7 @@ FreeElementData(ElementData *elementData) /*---------------------------------------------------------------------- * +++ Generic element implementation. - * + * * Used for elements which are handled entirely by the XP Theme API, * such as radiobutton and checkbutton indicators, scrollbar arrows, etc. */ @@ -489,10 +503,10 @@ static void GenericElementSize( if (SUCCEEDED(result)) { *widthPtr = size.cx; *heightPtr = size.cy; - } + } } - /* See NOTE-GetThemeMargins + /* See NOTE-GetThemeMargins */ *paddingPtr = elementData->info->padding; if (elementData->info->flags & PAD_MARGINS) { @@ -539,7 +553,7 @@ static Ttk_ElementSpec GenericElementSpec = /*---------------------------------------------------------------------- * +++ Sized element implementation. - * + * * Used for elements which are handled entirely by the XP Theme API, * but that require a fixed size adjustment. * Note that GetThemeSysSize calls through to GetSystemMetrics @@ -613,7 +627,7 @@ static Ttk_ElementSpec ThumbElementSpec = /*---------------------------------------------------------------------- * +++ 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. + * so that indeterminate progress bars show 3 bars instead of 1. */ static void PbarElementSize( @@ -646,14 +660,14 @@ static Ttk_ElementSpec PbarElementSpec = * +++ Notebook tab element. * Same as generic element, with additional logic to select * proper iPartID for the leftmost tab. - * - * Notes: TABP_TABITEMRIGHTEDGE (or TABP_TOPTABITEMRIGHTEDGE, + * + * 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 TILES_* definitions are identical, so + * The TIS_* and TILES_* definitions are identical, so * we can use the same statemap no matter what the partId. */ static void TabElementDraw( @@ -692,14 +706,22 @@ static Ttk_ElementSpec TabElementSpec = #define TTK_STATE_OPEN TTK_STATE_USER1 #define TTK_STATE_LEAF TTK_STATE_USER2 -static Ttk_StateTable header_statemap[] = +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[] = +static Ttk_StateTable treeview_statemap[] = +{ + { TREIS_DISABLED, TTK_STATE_DISABLED, 0 }, + { TREIS_SELECTED, TTK_STATE_SELECTED, 0}, + { TREIS_HOT, TTK_STATE_ACTIVE, 0 }, + { TREIS_NORMAL, 0,0 }, +}; + +static Ttk_StateTable tvpglyph_statemap[] = { { GLPS_OPENED, TTK_STATE_OPEN, 0 }, { GLPS_CLOSED, 0,0 }, @@ -729,11 +751,11 @@ static Ttk_ElementSpec TreeIndicatorElementSpec = *---------------------------------------------------------------------- * Text element (does not work yet). * - * According to "Using Windows XP Visual Styles", we need to select + * 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 @@ -828,7 +850,7 @@ TTK_BEGIN_LAYOUT_TABLE(LayoutTable) TTK_LAYOUT("TButton", TTK_GROUP("Button.button", TTK_FILL_BOTH, - TTK_GROUP("Button.focus", TTK_FILL_BOTH, + TTK_GROUP("Button.focus", TTK_FILL_BOTH, TTK_GROUP("Button.padding", TTK_FILL_BOTH, TTK_NODE("Button.label", TTK_FILL_BOTH))))) @@ -855,7 +877,7 @@ TTK_LAYOUT("Vertical.TScrollbar", TTK_LAYOUT("Horizontal.TScale", 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.track", TTK_FILL_X) TTK_NODE("Horizontal.Scale.slider", TTK_PACK_LEFT) ))) TTK_LAYOUT("Vertical.TScale", @@ -867,7 +889,7 @@ TTK_LAYOUT("Vertical.TScale", TTK_END_LAYOUT_TABLE /*---------------------------------------------------------------------- - * +++ XP element info table: + * +++ XP element info table: */ #define PAD(l,t,r,b) {l,t,r,b} @@ -935,7 +957,7 @@ static ElementInfo ElementInfoTable[] = { /* ttk::notebook */ { "tab", &TabElementSpec, L"TAB", TABP_TABITEM, tabitem_statemap, PAD(3,3,3,0), 0 }, - { "client", &GenericElementSpec, L"TAB", + { "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 }, @@ -945,15 +967,17 @@ static ElementInfo ElementInfoTable[] = { TP_SPLITBUTTON,toolbutton_statemap, NOPAD,0 }, { "Menubutton.dropdown", &GenericElementSpec, L"TOOLBAR", TP_SPLITBUTTONDROPDOWN,toolbutton_statemap, NOPAD,0 }, + { "Treeview.field", &GenericElementSpec, L"TREEVIEW", + TVP_TREEITEM, treeview_statemap, PAD(1, 1, 1, 1), 0 }, { "Treeitem.indicator", &TreeIndicatorElementSpec, L"TREEVIEW", TVP_GLYPH, tvpglyph_statemap, PAD(1,1,6,0), PAD_MARGINS }, - { "Treeheading.border", &GenericElementSpec, L"HEADER", + { "Treeheading.border", &GenericElementSpec, L"HEADER", HP_HEADERITEM, header_statemap, PAD(4,0,4,0),0 }, - { "sizegrip", &GenericElementSpec, L"STATUS", + { "sizegrip", &GenericElementSpec, L"STATUS", SP_GRIPPER, null_statemap, NOPAD,0 }, #if BROKEN_TEXT_ELEMENT - { "Labelframe.text", &TextElementSpec, L"BUTTON", + { "Labelframe.text", &TextElementSpec, L"BUTTON", BP_GROUPBOX, groupbox_statemap, NOPAD,0 }, #endif @@ -962,6 +986,152 @@ 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: */ @@ -970,8 +1140,12 @@ MODULE_SCOPE int TtkXPTheme_Init(Tcl_Interp *interp, HWND hwnd) XPThemeData *themeData; XPThemeProcs *procs; HINSTANCE hlibrary; - Ttk_Theme themePtr, parentPtr; + Ttk_Theme themePtr, parentPtr, vistaPtr; ElementInfo *infoPtr; + OSVERSIONINFO os; + + os.dwOSVersionInfoSize = sizeof(os); + GetVersionEx(&os); procs = LoadXPThemeProcs(&hlibrary); if (!procs) @@ -997,6 +1171,19 @@ 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); + + /* + * Create the vista theme on suitable platform versions and set the theme + * enable function. The theme itself is defined in script. + */ + + if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && os.dwMajorVersion > 5) { + vistaPtr = Ttk_CreateTheme(interp, "vista", themePtr); + if (vistaPtr) { + Ttk_SetThemeEnabledProc(vistaPtr, XPThemeEnabled, themeData); + } + } /* * New elements: -- cgit v0.12