ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

theme_button.c
Go to the documentation of this file.
00001 /*
00002  * Theming - Button control
00003  *
00004  * Copyright (c) 2008 by Reece H. Dunn
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00019  *
00020  */
00021 
00022 #include <stdarg.h>
00023 #include <string.h>
00024 #include <stdlib.h>
00025 
00026 #include "windef.h"
00027 #include "winbase.h"
00028 #include "wingdi.h"
00029 #include "winuser.h"
00030 #include "uxtheme.h"
00031 #include "vssym32.h"
00032 #include "comctl32.h"
00033 
00034 #define BUTTON_TYPE 0x0f /* bit mask for the available button types */
00035 
00036 /* These are indices into a states array to determine the theme state for a given theme part. */
00037 typedef enum
00038 {
00039     STATE_NORMAL,
00040     STATE_DISABLED,
00041     STATE_HOT,
00042     STATE_PRESSED,
00043     STATE_DEFAULTED
00044 } ButtonState;
00045 
00046 typedef void (*pfThemedPaint)(HTHEME theme, HWND hwnd, HDC hdc, ButtonState drawState, UINT dtFlags);
00047 
00048 static UINT get_drawtext_flags(DWORD style, DWORD ex_style)
00049 {
00050     UINT flags = 0;
00051 
00052     if (style & BS_PUSHLIKE)
00053         style &= ~BUTTON_TYPE;
00054 
00055     if (!(style & BS_MULTILINE))
00056         flags |= DT_SINGLELINE;
00057     else
00058         flags |= DT_WORDBREAK;
00059 
00060     switch (style & BS_CENTER)
00061     {
00062     case BS_LEFT:   flags |= DT_LEFT;   break;
00063     case BS_RIGHT:  flags |= DT_RIGHT;  break;
00064     case BS_CENTER: flags |= DT_CENTER; break;
00065     default:
00066         flags |= ((style & BUTTON_TYPE) <= BS_DEFPUSHBUTTON)
00067                ? DT_CENTER : DT_LEFT;
00068     }
00069 
00070     if (ex_style & WS_EX_RIGHT)
00071         flags = DT_RIGHT | (flags & ~(DT_LEFT | DT_CENTER));
00072 
00073     if ((style & BUTTON_TYPE) != BS_GROUPBOX)
00074     {
00075         switch (style & BS_VCENTER)
00076         {
00077         case BS_TOP:     flags |= DT_TOP;     break;
00078         case BS_BOTTOM:  flags |= DT_BOTTOM;  break;
00079         case BS_VCENTER: /* fall through */
00080         default:         flags |= DT_VCENTER; break;
00081         }
00082     }
00083     else
00084         /* GroupBox's text is always single line and is top aligned. */
00085         flags |= DT_SINGLELINE | DT_TOP;
00086 
00087     return flags;
00088 }
00089 
00090 static inline WCHAR *get_button_text(HWND hwnd)
00091 {
00092     INT len = 512;
00093     WCHAR *text;
00094     text = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
00095     if (text) InternalGetWindowText(hwnd, text, len + 1);
00096     return text;
00097 }
00098 
00099 static void PB_draw(HTHEME theme, HWND hwnd, HDC hDC, ButtonState drawState, UINT dtFlags)
00100 {
00101     static const int states[] = { PBS_NORMAL, PBS_DISABLED, PBS_HOT, PBS_PRESSED, PBS_DEFAULTED };
00102 
00103     RECT bgRect, textRect;
00104     HFONT font = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0);
00105     HFONT hPrevFont = font ? SelectObject(hDC, font) : NULL;
00106     int state = states[ drawState ];
00107     WCHAR *text = get_button_text(hwnd);
00108 
00109     GetClientRect(hwnd, &bgRect);
00110     GetThemeBackgroundContentRect(theme, hDC, BP_PUSHBUTTON, state, &bgRect, &textRect);
00111 
00112     if (IsThemeBackgroundPartiallyTransparent(theme, BP_PUSHBUTTON, state))
00113         DrawThemeParentBackground(hwnd, hDC, NULL);
00114     DrawThemeBackground(theme, hDC, BP_PUSHBUTTON, state, &bgRect, NULL);
00115     if (text)
00116     {
00117         DrawThemeText(theme, hDC, BP_PUSHBUTTON, state, text, lstrlenW(text), dtFlags, 0, &textRect);
00118         HeapFree(GetProcessHeap(), 0, text);
00119     }
00120 
00121     if (hPrevFont) SelectObject(hDC, hPrevFont);
00122 }
00123 
00124 static void CB_draw(HTHEME theme, HWND hwnd, HDC hDC, ButtonState drawState, UINT dtFlags)
00125 {
00126     static const int cb_states[3][5] =
00127     {
00128         { CBS_UNCHECKEDNORMAL, CBS_UNCHECKEDDISABLED, CBS_UNCHECKEDHOT, CBS_UNCHECKEDPRESSED, CBS_UNCHECKEDNORMAL },
00129         { CBS_CHECKEDNORMAL, CBS_CHECKEDDISABLED, CBS_CHECKEDHOT, CBS_CHECKEDPRESSED, CBS_CHECKEDNORMAL },
00130         { CBS_MIXEDNORMAL, CBS_MIXEDDISABLED, CBS_MIXEDHOT, CBS_MIXEDPRESSED, CBS_MIXEDNORMAL }
00131     };
00132 
00133     static const int rb_states[2][5] =
00134     {
00135         { RBS_UNCHECKEDNORMAL, RBS_UNCHECKEDDISABLED, RBS_UNCHECKEDHOT, RBS_UNCHECKEDPRESSED, RBS_UNCHECKEDNORMAL },
00136         { RBS_CHECKEDNORMAL, RBS_CHECKEDDISABLED, RBS_CHECKEDHOT, RBS_CHECKEDPRESSED, RBS_CHECKEDNORMAL }
00137     };
00138 
00139     static const int cb_size = 13;
00140 
00141     RECT bgRect, textRect;
00142     HFONT font = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0);
00143     HFONT hPrevFont = font ? SelectObject(hDC, font) : NULL;
00144     LRESULT checkState = SendMessageW(hwnd, BM_GETCHECK, 0, 0);
00145     DWORD dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
00146     int part = ((dwStyle & BUTTON_TYPE) == BS_RADIOBUTTON) || ((dwStyle & BUTTON_TYPE) == BS_AUTORADIOBUTTON)
00147              ? BP_RADIOBUTTON
00148              : BP_CHECKBOX;
00149     int state = (part == BP_CHECKBOX)
00150               ? cb_states[ checkState ][ drawState ]
00151               : rb_states[ checkState ][ drawState ];
00152     WCHAR *text = get_button_text(hwnd);
00153 
00154     GetClientRect(hwnd, &bgRect);
00155     GetThemeBackgroundContentRect(theme, hDC, part, state, &bgRect, &textRect);
00156 
00157     if (dtFlags & DT_SINGLELINE) /* Center the checkbox / radio button to the text. */
00158         bgRect.top = bgRect.top + (textRect.bottom - textRect.top - cb_size) / 2;
00159 
00160     /* adjust for the check/radio marker */
00161     bgRect.bottom = bgRect.top + cb_size;
00162     bgRect.right = bgRect.left + cb_size;
00163     textRect.left = bgRect.right + 6;
00164 
00165     if (IsThemeBackgroundPartiallyTransparent(theme, part, state))
00166         DrawThemeParentBackground(hwnd, hDC, NULL);
00167     DrawThemeBackground(theme, hDC, part, state, &bgRect, NULL);
00168     if (text)
00169     {
00170         DrawThemeText(theme, hDC, part, state, text, lstrlenW(text), dtFlags, 0, &textRect);
00171         HeapFree(GetProcessHeap(), 0, text);
00172     }
00173 
00174     if (hPrevFont) SelectObject(hDC, hPrevFont);
00175 }
00176 
00177 static void GB_draw(HTHEME theme, HWND hwnd, HDC hDC, ButtonState drawState, UINT dtFlags)
00178 {
00179     static const int states[] = { GBS_NORMAL, GBS_DISABLED, GBS_NORMAL, GBS_NORMAL, GBS_NORMAL };
00180 
00181     RECT bgRect, textRect, contentRect;
00182     HFONT font = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0);
00183     HFONT hPrevFont = font ? SelectObject(hDC, font) : NULL;
00184     int state = states[ drawState ];
00185     WCHAR *text = get_button_text(hwnd);
00186 
00187     GetClientRect(hwnd, &bgRect);
00188     textRect = bgRect;
00189 
00190     if (text)
00191     {
00192         SIZE textExtent;
00193         GetTextExtentPoint32W(hDC, text, lstrlenW(text), &textExtent);
00194         bgRect.top += (textExtent.cy / 2);
00195         textRect.left += 10;
00196         textRect.bottom = textRect.top + textExtent.cy;
00197         textRect.right = textRect.left + textExtent.cx + 4;
00198 
00199         ExcludeClipRect(hDC, textRect.left, textRect.top, textRect.right, textRect.bottom);
00200     }
00201 
00202     GetThemeBackgroundContentRect(theme, hDC, BP_GROUPBOX, state, &bgRect, &contentRect);
00203     ExcludeClipRect(hDC, contentRect.left, contentRect.top, contentRect.right, contentRect.bottom);
00204 
00205     if (IsThemeBackgroundPartiallyTransparent(theme, BP_GROUPBOX, state))
00206         DrawThemeParentBackground(hwnd, hDC, NULL);
00207     DrawThemeBackground(theme, hDC, BP_GROUPBOX, state, &bgRect, NULL);
00208 
00209     SelectClipRgn(hDC, NULL);
00210 
00211     if (text)
00212     {
00213         textRect.left += 2;
00214         textRect.right -= 2;
00215         DrawThemeText(theme, hDC, BP_GROUPBOX, state, text, lstrlenW(text), 0, 0, &textRect);
00216         HeapFree(GetProcessHeap(), 0, text);
00217     }
00218 
00219     if (hPrevFont) SelectObject(hDC, hPrevFont);
00220 }
00221 
00222 static const pfThemedPaint btnThemedPaintFunc[BUTTON_TYPE + 1] =
00223 {
00224     PB_draw, /* BS_PUSHBUTTON */
00225     PB_draw, /* BS_DEFPUSHBUTTON */
00226     CB_draw, /* BS_CHECKBOX */
00227     CB_draw, /* BS_AUTOCHECKBOX */
00228     CB_draw, /* BS_RADIOBUTTON */
00229     CB_draw, /* BS_3STATE */
00230     CB_draw, /* BS_AUTO3STATE */
00231     GB_draw, /* BS_GROUPBOX */
00232     NULL, /* BS_USERBUTTON */
00233     CB_draw, /* BS_AUTORADIOBUTTON */
00234     NULL, /* Not defined */
00235     NULL, /* BS_OWNERDRAW */
00236     NULL, /* Not defined */
00237     NULL, /* Not defined */
00238     NULL, /* Not defined */
00239     NULL, /* Not defined */
00240 };
00241 
00242 static BOOL BUTTON_Paint(HTHEME theme, HWND hwnd, HDC hParamDC)
00243 {
00244     PAINTSTRUCT ps;
00245     HDC hDC;
00246     DWORD dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
00247     DWORD dwStyleEx = GetWindowLongW(hwnd, GWL_EXSTYLE);
00248     UINT dtFlags = get_drawtext_flags(dwStyle, dwStyleEx);
00249     int state = (int)SendMessageW(hwnd, BM_GETSTATE, 0, 0);
00250     ButtonState drawState;
00251     pfThemedPaint paint = btnThemedPaintFunc[ dwStyle & BUTTON_TYPE ];
00252 
00253     if(!paint)
00254         return FALSE;
00255 
00256     if(IsWindowEnabled(hwnd))
00257     {
00258         if(state & BST_PUSHED) drawState = STATE_PRESSED;
00259         else if(state & BST_HOT) drawState = STATE_HOT;
00260         else if(state & BST_FOCUS) drawState = STATE_DEFAULTED;
00261         else drawState = STATE_NORMAL;
00262     }
00263     else drawState = STATE_DISABLED;
00264 
00265     hDC = hParamDC ? hParamDC : BeginPaint(hwnd, &ps);
00266     paint(theme, hwnd, hDC, drawState, dtFlags);
00267     if (!hParamDC) EndPaint(hwnd, &ps);
00268     return TRUE;
00269 }
00270 
00271 /**********************************************************************
00272  * The button control subclass window proc.
00273  */
00274 LRESULT CALLBACK THEMING_ButtonSubclassProc(HWND hwnd, UINT msg,
00275                                             WPARAM wParam, LPARAM lParam,
00276                                             ULONG_PTR dwRefData)
00277 {
00278     const WCHAR* themeClass = WC_BUTTONW;
00279     HTHEME theme;
00280     LRESULT result;
00281 
00282     switch (msg)
00283     {
00284     case WM_CREATE:
00285         result = THEMING_CallOriginalClass(hwnd, msg, wParam, lParam);
00286         OpenThemeData(hwnd, themeClass);
00287         return result;
00288 
00289     case WM_DESTROY:
00290         theme = GetWindowTheme(hwnd);
00291         CloseThemeData (theme);
00292         return THEMING_CallOriginalClass(hwnd, msg, wParam, lParam);
00293 
00294     case WM_THEMECHANGED:
00295         theme = GetWindowTheme(hwnd);
00296         CloseThemeData (theme);
00297         OpenThemeData(hwnd, themeClass);
00298         break;
00299 
00300     case WM_SYSCOLORCHANGE:
00301         theme = GetWindowTheme(hwnd);
00302     if (!theme) return THEMING_CallOriginalClass(hwnd, msg, wParam, lParam);
00303         /* Do nothing. When themed, a WM_THEMECHANGED will be received, too,
00304      * which will do the repaint. */
00305         break;
00306 
00307     case WM_PAINT:
00308         theme = GetWindowTheme(hwnd);
00309         if (theme && BUTTON_Paint(theme, hwnd, (HDC)wParam))
00310             return 0;
00311         else
00312             return THEMING_CallOriginalClass(hwnd, msg, wParam, lParam);
00313 
00314     case WM_ENABLE:
00315         theme = GetWindowTheme(hwnd);
00316         if (theme) RedrawWindow(hwnd, NULL, NULL,
00317                                 RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW);
00318         return THEMING_CallOriginalClass(hwnd, msg, wParam, lParam);
00319 
00320     case WM_MOUSEMOVE:
00321     {
00322         TRACKMOUSEEVENT mouse_event;
00323         mouse_event.cbSize = sizeof(TRACKMOUSEEVENT);
00324         mouse_event.dwFlags = TME_QUERY;
00325         if(!TrackMouseEvent(&mouse_event) || !(mouse_event.dwFlags&(TME_HOVER|TME_LEAVE)))
00326         {
00327             mouse_event.dwFlags = TME_HOVER|TME_LEAVE;
00328             mouse_event.hwndTrack = hwnd;
00329             mouse_event.dwHoverTime = 1;
00330             TrackMouseEvent(&mouse_event);
00331         }
00332         break;
00333     }
00334 
00335     case WM_MOUSEHOVER:
00336     {
00337         int state = (int)SendMessageW(hwnd, BM_GETSTATE, 0, 0);
00338         SetWindowLongW(hwnd, 0, state|BST_HOT);
00339         InvalidateRect(hwnd, NULL, FALSE);
00340         break;
00341     }
00342 
00343     case WM_MOUSELEAVE:
00344     {
00345         int state = (int)SendMessageW(hwnd, BM_GETSTATE, 0, 0);
00346         SetWindowLongW(hwnd, 0, state&(~BST_HOT));
00347         InvalidateRect(hwnd, NULL, FALSE);
00348         break;
00349     }
00350 
00351     default:
00352     /* Call old proc */
00353     return THEMING_CallOriginalClass(hwnd, msg, wParam, lParam);
00354     }
00355     return 0;
00356 }

Generated on Sat May 26 2012 04:21:38 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.