Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygentheme_combo.c
Go to the documentation of this file.
00001 /* 00002 * Theming - Combo box control 00003 * 00004 * Copyright (c) 2005 by Frank Richter 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 #include "wine/debug.h" 00034 00035 WINE_DEFAULT_DEBUG_CHANNEL(themingcombo); 00036 00037 /* Subclass-private state flags */ 00038 #define STATE_NOREDRAW 1 00039 #define STATE_HOT 2 00040 00041 /* some constants for metrics, same as in user32 */ 00042 #define COMBO_XBORDERSIZE 2 00043 #define COMBO_YBORDERSIZE 2 00044 #define COMBO_EDITBUTTONSPACE 0 00045 #define EDIT_CONTROL_PADDING 1 00046 00047 /* paint text of combobox, needed for read-only drop downs. */ 00048 static void paint_text (HWND hwnd, HDC hdc, DWORD dwStyle, const COMBOBOXINFO *cbi) 00049 { 00050 INT id, size = 0; 00051 LPWSTR pText = NULL; 00052 UINT itemState = ODS_COMBOBOXEDIT; 00053 HFONT font = (HFONT)SendMessageW (hwnd, WM_GETFONT, 0, 0); 00054 HFONT hPrevFont = (font) ? SelectObject(hdc, font) : 0; 00055 RECT rectEdit; 00056 BOOL focused = GetFocus () == hwnd; 00057 BOOL dropped = cbi->stateButton == STATE_SYSTEM_PRESSED; 00058 00059 TRACE("\n"); 00060 00061 /* follow Windows combobox that sends a bunch of text 00062 * inquiries to its listbox while processing WM_PAINT. */ 00063 00064 if( (id = SendMessageW (cbi->hwndList, LB_GETCURSEL, 0, 0) ) != LB_ERR ) 00065 { 00066 size = SendMessageW (cbi->hwndList, LB_GETTEXTLEN, id, 0); 00067 if (size == LB_ERR) 00068 FIXME("LB_ERR probably not handled yet\n"); 00069 if( (pText = HeapAlloc( GetProcessHeap(), 0, (size + 1) * sizeof(WCHAR))) ) 00070 { 00071 /* size from LB_GETTEXTLEN may be too large, from LB_GETTEXT is accurate */ 00072 size = SendMessageW (cbi->hwndList, LB_GETTEXT, id, (LPARAM)pText); 00073 pText[size] = '\0'; /* just in case */ 00074 } else return; 00075 } 00076 else 00077 if( !(dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) ) 00078 return; 00079 00080 /* 00081 * Give ourselves some space. 00082 */ 00083 CopyRect (&rectEdit, &cbi->rcItem); 00084 InflateRect( &rectEdit, -1, -1 ); 00085 00086 if(dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) 00087 { 00088 DRAWITEMSTRUCT dis; 00089 HRGN clipRegion; 00090 UINT ctlid = (UINT)GetWindowLongPtrW( hwnd, GWLP_ID ); 00091 00092 /* setup state for DRAWITEM message. Owner will highlight */ 00093 if ( focused && !dropped ) 00094 itemState |= ODS_SELECTED | ODS_FOCUS; 00095 00096 /* 00097 * Save the current clip region. 00098 * To retrieve the clip region, we need to create one "dummy" 00099 * clip region. 00100 */ 00101 clipRegion = CreateRectRgnIndirect(&rectEdit); 00102 00103 if (GetClipRgn(hdc, clipRegion)!=1) 00104 { 00105 DeleteObject(clipRegion); 00106 clipRegion=NULL; 00107 } 00108 00109 if (!IsWindowEnabled(hwnd)) itemState |= ODS_DISABLED; 00110 00111 dis.CtlType = ODT_COMBOBOX; 00112 dis.CtlID = ctlid; 00113 dis.hwndItem = hwnd; 00114 dis.itemAction = ODA_DRAWENTIRE; 00115 dis.itemID = id; 00116 dis.itemState = itemState; 00117 dis.hDC = hdc; 00118 dis.rcItem = rectEdit; 00119 dis.itemData = SendMessageW(cbi->hwndList, LB_GETITEMDATA, id, 0); 00120 00121 /* 00122 * Clip the DC and have the parent draw the item. 00123 */ 00124 IntersectClipRect(hdc, 00125 rectEdit.left, rectEdit.top, 00126 rectEdit.right, rectEdit.bottom); 00127 00128 SendMessageW(GetParent (hwnd), WM_DRAWITEM, ctlid, (LPARAM)&dis ); 00129 00130 /* 00131 * Reset the clipping region. 00132 */ 00133 SelectClipRgn(hdc, clipRegion); 00134 } 00135 else 00136 { 00137 static const WCHAR empty_stringW[] = { 0 }; 00138 00139 if ( focused && !dropped ) { 00140 00141 /* highlight */ 00142 FillRect( hdc, &rectEdit, GetSysColorBrush(COLOR_HIGHLIGHT) ); 00143 SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) ); 00144 SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) ); 00145 } 00146 00147 ExtTextOutW( hdc, 00148 rectEdit.left + 1, 00149 rectEdit.top + 1, 00150 ETO_OPAQUE | ETO_CLIPPED, 00151 &rectEdit, 00152 pText ? pText : empty_stringW , size, NULL ); 00153 00154 if ( focused && !dropped ) 00155 DrawFocusRect( hdc, &rectEdit ); 00156 } 00157 00158 if( hPrevFont ) 00159 SelectObject(hdc, hPrevFont ); 00160 00161 HeapFree( GetProcessHeap(), 0, pText ); 00162 } 00163 00164 /* paint the combobox */ 00165 static LRESULT paint (HTHEME theme, HWND hwnd, HDC hParamDC, ULONG state) 00166 { 00167 PAINTSTRUCT ps; 00168 HDC hDC; 00169 COMBOBOXINFO cbi; 00170 DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE); 00171 00172 hDC = (hParamDC) ? hParamDC 00173 : BeginPaint( hwnd, &ps); 00174 00175 TRACE("hdc=%p\n", hDC); 00176 00177 if( hDC && !(state & STATE_NOREDRAW) ) 00178 { 00179 RECT frameRect; 00180 int buttonState; 00181 00182 cbi.cbSize = sizeof (cbi); 00183 SendMessageW (hwnd, CB_GETCOMBOBOXINFO, 0, (LPARAM)&cbi); 00184 00185 /* paint border */ 00186 if ((dwStyle & CBS_DROPDOWNLIST) != CBS_SIMPLE) 00187 GetClientRect (hwnd, &frameRect); 00188 else 00189 { 00190 CopyRect (&frameRect, &cbi.rcItem); 00191 00192 InflateRect(&frameRect, 00193 EDIT_CONTROL_PADDING + COMBO_XBORDERSIZE, 00194 EDIT_CONTROL_PADDING + COMBO_YBORDERSIZE); 00195 } 00196 00197 DrawThemeBackground (theme, hDC, 0, 00198 IsWindowEnabled (hwnd) ? CBXS_NORMAL : CBXS_DISABLED, &frameRect, NULL); 00199 00200 /* paint button */ 00201 if (cbi.stateButton != STATE_SYSTEM_INVISIBLE) 00202 { 00203 if (!IsWindowEnabled (hwnd)) 00204 buttonState = CBXS_DISABLED; 00205 else if (cbi.stateButton == STATE_SYSTEM_PRESSED) 00206 buttonState = CBXS_PRESSED; 00207 else if (state & STATE_HOT) 00208 buttonState = CBXS_HOT; 00209 else 00210 buttonState = CBXS_NORMAL; 00211 DrawThemeBackground (theme, hDC, CP_DROPDOWNBUTTON, buttonState, 00212 &cbi.rcButton, NULL); 00213 } 00214 00215 /* paint text, if we need to */ 00216 if ((dwStyle & CBS_DROPDOWNLIST) == CBS_DROPDOWNLIST) 00217 paint_text (hwnd, hDC, dwStyle, &cbi); 00218 } 00219 00220 if( !hParamDC ) 00221 EndPaint(hwnd, &ps); 00222 00223 return 0; 00224 } 00225 00226 00227 /********************************************************************** 00228 * The combo control subclass window proc. 00229 */ 00230 LRESULT CALLBACK THEMING_ComboSubclassProc (HWND hwnd, UINT msg, 00231 WPARAM wParam, LPARAM lParam, 00232 ULONG_PTR dwRefData) 00233 { 00234 const WCHAR* themeClass = WC_COMBOBOXW; 00235 HTHEME theme; 00236 LRESULT result; 00237 00238 switch (msg) 00239 { 00240 case WM_CREATE: 00241 result = THEMING_CallOriginalClass (hwnd, msg, wParam, lParam); 00242 OpenThemeData( hwnd, themeClass ); 00243 return result; 00244 00245 case WM_DESTROY: 00246 theme = GetWindowTheme( hwnd ); 00247 CloseThemeData ( theme ); 00248 return THEMING_CallOriginalClass (hwnd, msg, wParam, lParam); 00249 00250 case WM_THEMECHANGED: 00251 theme = GetWindowTheme( hwnd ); 00252 CloseThemeData ( theme ); 00253 OpenThemeData( hwnd, themeClass ); 00254 break; 00255 00256 case WM_SYSCOLORCHANGE: 00257 theme = GetWindowTheme( hwnd ); 00258 if (!theme) return THEMING_CallOriginalClass (hwnd, msg, wParam, lParam); 00259 /* Do nothing. When themed, a WM_THEMECHANGED will be received, too, 00260 * which will do the repaint. */ 00261 break; 00262 00263 case WM_PAINT: 00264 theme = GetWindowTheme( hwnd ); 00265 if (!theme) return THEMING_CallOriginalClass (hwnd, msg, wParam, lParam); 00266 return paint (theme, hwnd, (HDC)wParam, dwRefData); 00267 00268 case WM_SETREDRAW: 00269 /* Since there doesn't seem to be WM_GETREDRAW, do redraw tracking in 00270 * the subclass as well. */ 00271 if( wParam ) 00272 dwRefData &= ~STATE_NOREDRAW; 00273 else 00274 dwRefData |= STATE_NOREDRAW; 00275 THEMING_SetSubclassData (hwnd, dwRefData); 00276 return THEMING_CallOriginalClass (hwnd, msg, wParam, lParam); 00277 00278 case WM_MOUSEMOVE: 00279 { 00280 /* Dropdown button hot-tracking */ 00281 COMBOBOXINFO cbi; 00282 POINT pt; 00283 00284 pt.x = (short)LOWORD(lParam); 00285 pt.y = (short)HIWORD(lParam); 00286 cbi.cbSize = sizeof (cbi); 00287 SendMessageW (hwnd, CB_GETCOMBOBOXINFO, 0, (LPARAM)&cbi); 00288 00289 if (cbi.stateButton != STATE_SYSTEM_INVISIBLE) 00290 { 00291 if (PtInRect (&cbi.rcButton, pt)) 00292 { 00293 if (!(dwRefData & STATE_HOT)) 00294 { 00295 dwRefData |= STATE_HOT; 00296 THEMING_SetSubclassData (hwnd, dwRefData); 00297 RedrawWindow (hwnd, &cbi.rcButton, 0, 00298 RDW_INVALIDATE | RDW_UPDATENOW); 00299 } 00300 } 00301 else 00302 { 00303 if (dwRefData & STATE_HOT) 00304 { 00305 dwRefData &= ~STATE_HOT; 00306 THEMING_SetSubclassData (hwnd, dwRefData); 00307 RedrawWindow (hwnd, &cbi.rcButton, 0, 00308 RDW_INVALIDATE | RDW_UPDATENOW); 00309 } 00310 } 00311 } 00312 } 00313 return THEMING_CallOriginalClass (hwnd, msg, wParam, lParam); 00314 00315 default: 00316 /* Call old proc */ 00317 return THEMING_CallOriginalClass (hwnd, msg, wParam, lParam); 00318 } 00319 return 0; 00320 } Generated on Thu May 24 2012 04:23:27 for ReactOS by
1.7.6.1
|