Attempt to make buttons themed

Frank Richter resqu at gmx.ch
Mon Mar 21 13:05:57 CST 2005


Hi,
to see how easy (or not) it would be to make the controls use themes, I 
tried to get themed buttons; the result is the attached patch (to try it 
out, you need an .msstyles file and appropriate registry setup). It's 
probably not perfect as it is, comments/questions are welcome.

Screenshot:
http://img87.exs.cx/my.php?loc=img87&image=winewiththemedbuttons3xh.png

Some funny side effect when theming is enabled: applications show up in 
standard colors, but as soon as the first button is created, the colors 
switch to the theme's colors. I guess opening the theme data in the 
button code triggers some uxtheme initialization that in turn changes 
the system colors.

Also, all applications get themed buttons, which diverges from WinXPs 
behaviour and may or may not be desired for some apps.

-f.r.
-------------- next part --------------
Index: dlls/user/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/user/Makefile.in,v
retrieving revision 1.88
diff -u -r1.88 Makefile.in
--- dlls/user/Makefile.in	10 Mar 2005 15:47:53 -0000	1.88
+++ dlls/user/Makefile.in	21 Mar 2005 18:46:31 -0000
@@ -4,7 +4,7 @@
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = user32.dll
-IMPORTS   = gdi32 advapi32 kernel32 ntdll
+IMPORTS   = gdi32 advapi32 kernel32 uxtheme ntdll
 EXTRALIBS = $(LIBUNICODE)
 
 SPEC_SRCS16 = \
Index: dlls/user/button.c
===================================================================
RCS file: /home/wine/wine/dlls/user/button.c,v
retrieving revision 1.6
diff -u -r1.6 button.c
--- dlls/user/button.c	23 Dec 2004 17:21:05 -0000	1.6
+++ dlls/user/button.c	21 Mar 2005 18:46:32 -0000
@@ -71,6 +71,9 @@
 #include "windef.h"
 #include "winbase.h"
 #include "wingdi.h"
+#include "winuser.h" /* Indirectly required by uxtheme.h */
+#include "uxtheme.h"
+#include "tmschema.h"
 #include "wine/winuser16.h"
 #include "controls.h"
 #include "user_private.h"
@@ -79,7 +82,8 @@
 #define STATE_GWL_OFFSET  0
 #define HFONT_GWL_OFFSET  (sizeof(LONG))
 #define HIMAGE_GWL_OFFSET (HFONT_GWL_OFFSET+sizeof(HFONT))
-#define NB_EXTRA_BYTES    (HIMAGE_GWL_OFFSET+sizeof(HANDLE))
+#define HTHEME_GWL_OFFSET (HIMAGE_GWL_OFFSET+sizeof(HANDLE))
+#define NB_EXTRA_BYTES    (HTHEME_GWL_OFFSET+sizeof(HTHEME))
 
   /* Button state values */
 #define BUTTON_UNCHECKED       0x00
@@ -95,6 +99,7 @@
 
 static UINT BUTTON_CalcLabelRect( HWND hwnd, HDC hdc, RECT *rc );
 static void PB_Paint( HWND hwnd, HDC hDC, UINT action );
+static void PB_PaintThemed( HWND hwnd, HDC hDC, UINT action );
 static void CB_Paint( HWND hwnd, HDC hDC, UINT action );
 static void GB_Paint( HWND hwnd, HDC hDC, UINT action );
 static void UB_Paint( HWND hwnd, HDC hDC, UINT action );
@@ -123,7 +128,7 @@
 
 typedef void (*pfPaint)( HWND hwnd, HDC hdc, UINT action );
 
-static const pfPaint btnPaintFunc[MAX_BTN_TYPE] =
+static const pfPaint btnUnthemedPaintFunc[MAX_BTN_TYPE] =
 {
     PB_Paint,    /* BS_PUSHBUTTON */
     PB_Paint,    /* BS_DEFPUSHBUTTON */
@@ -139,6 +144,22 @@
     OB_Paint     /* BS_OWNERDRAW */
 };
 
+static const pfPaint btnThemedPaintFunc[MAX_BTN_TYPE] =
+{
+    PB_PaintThemed,    	/* BS_PUSHBUTTON */
+    PB_PaintThemed,    	/* BS_DEFPUSHBUTTON */
+    CB_Paint,    	/* BS_CHECKBOX */
+    CB_Paint,    	/* BS_AUTOCHECKBOX */
+    CB_Paint,    	/* BS_RADIOBUTTON */
+    CB_Paint,    	/* BS_3STATE */
+    CB_Paint,    	/* BS_AUTO3STATE */
+    GB_Paint,    	/* BS_GROUPBOX */
+    UB_Paint,    	/* BS_USERBUTTON */
+    CB_Paint,    	/* BS_AUTORADIOBUTTON */
+    NULL,        	/* Not defined */
+    OB_Paint     	/* BS_OWNERDRAW */
+};
+
 static HBITMAP hbitmapCheckBoxes = 0;
 static WORD checkBoxWidth = 0, checkBoxHeight = 0;
 
@@ -183,9 +204,26 @@
     return (window_style & 0x0f);
 }
 
+inline static HTHEME get_button_theme( HWND hwnd )
+{
+    return (HTHEME)GetWindowLongPtrW( hwnd, HTHEME_GWL_OFFSET );
+}
+
+inline static void set_button_theme( HWND hwnd, HTHEME theme )
+{
+    SetWindowLongPtrW( hwnd, HTHEME_GWL_OFFSET, (ULONG_PTR)theme );
+}
+
+inline static const pfPaint* get_paint_funcs ( HWND hwnd )
+{
+    HTHEME theme = get_button_theme( hwnd );
+    return ( theme != NULL ) ? btnThemedPaintFunc : btnUnthemedPaintFunc;
+}
+
 /* paint a button of any type */
 inline static void paint_button( HWND hwnd, LONG style, UINT action )
 {
+    const pfPaint* btnPaintFunc = get_paint_funcs( hwnd );
     if (btnPaintFunc[style] && IsWindowVisible(hwnd))
     {
         HDC hdc = GetDC( hwnd );
@@ -215,6 +253,9 @@
     UINT btn_type = get_button_type( style );
     LONG state;
     HANDLE oldHbitmap;
+    static const WCHAR themeClass[] = { 'B','u','t','t','o','n',0 };
+    HTHEME theme;
+    const pfPaint* btnPaintFunc = get_paint_funcs( hWnd );
 
     pt.x = LOWORD(lParam);
     pt.y = HIWORD(lParam);
@@ -249,8 +290,24 @@
         if (btn_type >= MAX_BTN_TYPE)
             return -1; /* abort */
         set_button_state( hWnd, BUTTON_UNCHECKED );
+	theme = OpenThemeData( hWnd, themeClass );
+	set_button_theme( hWnd, theme );
         return 0;
+	
+    case WM_DESTROY:
+	theme = get_button_theme( hWnd );
+	if ( theme != NULL )
+	    CloseThemeData ( theme );
+	break;
 
+    case WM_THEMECHANGED:
+	theme = get_button_theme( hWnd );
+	if ( theme != NULL )
+	    CloseThemeData ( theme );
+	theme = OpenThemeData( hWnd, themeClass );
+	set_button_theme( hWnd, theme );
+	break;	
+	
     case WM_ERASEBKGND:
         if (btn_type == BS_OWNERDRAW)
         {
@@ -842,6 +899,39 @@
     SetBkMode(hDC, oldBkMode);
 }
 
+static void PB_PaintThemed( HWND hwnd, HDC hDC, UINT action )
+{
+    LONG    	state 		= get_button_state( hwnd );
+    LONG 	style 		= GetWindowLongW( hwnd, GWL_STYLE );
+    BOOL    	pushedState 	= (state & BUTTON_HIGHLIGHTED);
+    HTHEME 	theme 		= get_button_theme( hwnd );
+    int 	partID 		= BP_PUSHBUTTON;
+    int 	stateID;
+    RECT 	rc;
+    WCHAR 	*text 		= NULL;
+    BOOL 	disabledState 	= !IsWindowEnabled( hwnd );
+
+    GetClientRect( hwnd, &rc );
+    if (disabledState)
+	stateID = PBS_DISABLED;
+    else if (pushedState)
+	stateID = PBS_PRESSED;
+    else if (( get_button_type(style) == BS_DEFPUSHBUTTON )
+      || ( state & BUTTON_HASFOCUS ))
+	stateID = PBS_DEFAULTED;
+    else
+	stateID = PBS_NORMAL;
+
+    DrawThemeBackground( theme, hDC, partID, stateID, &rc, NULL);
+    
+    if (( text = get_button_text( hwnd ) ) != NULL )
+    {
+	if ((style & (BS_ICON|BS_BITMAP)) == BS_TEXT)
+	    DrawThemeText( theme, hDC, partID, stateID, text, -1, 
+	      BUTTON_BStoDT(style), 0, &rc );
+    }
+}
+
 /**********************************************************************
  *       Check Box & Radio Button Functions
  */


More information about the wine-devel mailing list