1 #include <windows.h>
2 #include <uxtheme.h>
3 #include <stdlib.h>
4 #include <tchar.h>
5 #include "resource.h"
6 
7 LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
8 
9 HICON hico;
10 HBITMAP hbmp;
11 HIMAGELIST himl;
12 POINT scPos;
13 
14 HBRUSH hbrNULL;
15 HBRUSH hbrRed;
16 HBRUSH hbrGreen;
17 HBRUSH hbrBlue;
18 HBRUSH hbrCyan;
19 HBRUSH hbrYellow;
20 
21 HBRUSH hbrCtlColorStatic;
22 HBRUSH hbrCtlColorBtn;
23 HBRUSH hbrPrintClientClear;
24 HBRUSH hbrErase;
25 
26 BOOL bSkipErase;
27 BOOL bSkipPaint;
28 
29 static void RegisterMyClass(HINSTANCE hInst)
30 {
31 	WNDCLASSEXW wcex;
32 
33 	wcex.cbSize = sizeof(WNDCLASSEX);
34 
35 	wcex.style = CS_HREDRAW | CS_VREDRAW;
36 	wcex.lpfnWndProc = WndProc;
37 	wcex.cbClsExtra = 0;
38 	wcex.cbWndExtra = 0;
39 	wcex.hInstance = hInst;
40 	wcex.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_WIN32PROJECT1));
41 	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
42 	wcex.hbrBackground = NULL;
43 	wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_MENU);
44 	wcex.lpszClassName = L"ButtonTests";
45 	wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
46 
47 	RegisterClassExW(&wcex);
48 }
49 
50 #define TOP_MARGIN 50
51 #define LEFT_MARGIN 160
52 #define X_GAP 10
53 #define Y_GAP 10
54 #define Y_HEIGHT 40
55 #define X_WIDTH 150
56 
57 static HWND CreateWnd(HWND hWnd, LPCWSTR Class, LPCWSTR Text, LONG style, int i, int j)
58 {
59 	return 	CreateWindowW(Class,
60 						  Text,
61 						  style | WS_CHILD | WS_VISIBLE,
62 						  LEFT_MARGIN + (X_GAP + X_WIDTH) * i,
63 						  TOP_MARGIN + ((Y_GAP + Y_HEIGHT)  *j),
64 						  X_WIDTH,
65 						  Y_HEIGHT,
66 						  hWnd, NULL, NULL, NULL);
67 }
68 
69 static HWND CreateBtn(HWND hWnd, LPCWSTR Text, LONG style, int i, int j)
70 {
71     WCHAR buffer[100];
72     SIZE s;
73 
74 	HWND ret = CreateWnd(hWnd, L"Button", Text, style, i, j);
75     if (GetWindowLongW(ret, GWL_STYLE) != (style | WS_CHILD | WS_VISIBLE))
76     {
77         swprintf(buffer, L"expected 0x%x got 0x%x", (style | WS_CHILD | WS_VISIBLE), GetWindowLongW(ret, GWL_STYLE));
78         MessageBox(0, buffer, L"error", MB_OK);
79     }
80 
81     if (SendMessageW(ret, BCM_GETIDEALSIZE, 0, (LPARAM)&s))
82     {
83         swprintf(buffer, L"%s (%d, %d)", Text, s.cx, s.cy);
84         SendMessageW(ret, WM_SETTEXT, 0, (LPARAM)buffer);
85     }
86     return ret;
87 }
88 
89 static void CreateButtonSet(HWND hwndParent, HWND *ahwnd, int i, int j, DWORD style)
90 {
91 	ahwnd[0] = CreateBtn(hwndParent, L"TestButton", style, i, j + 0);
92 	ahwnd[1] = CreateBtn(hwndParent, L"TestButton1", style, i, j + 1);
93 	ahwnd[2] = CreateBtn(hwndParent, L"TestButton2", style, i, j + 2);
94 	ahwnd[3] = CreateBtn(hwndParent, L"TestButton3", style | BS_BITMAP, i, j + 3);
95 	ahwnd[4] = CreateBtn(hwndParent, L"TestButton4", style | BS_ICON, i, j + 4);
96 
97 	SendMessageW(ahwnd[1], BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp);
98 	SendMessageW(ahwnd[2], BM_SETIMAGE, IMAGE_ICON, (LPARAM)hico);
99 
100 	SendMessageW(ahwnd[3], BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp);
101 	SendMessageW(ahwnd[4], BM_SETIMAGE, IMAGE_ICON, (LPARAM)hico);
102 }
103 
104 int WINAPI wWinMain(_In_ HINSTANCE hInstance,
105                      _In_opt_ HINSTANCE hPrevInstance,
106                      _In_ LPWSTR    lpCmdLine,
107                      _In_ int       nCmdShow)
108 {
109 	HWND hwnd[200];
110 	HANDLE hActCtx;
111 	ULONG_PTR cookie;
112 	BOOL bActivated;
113 
114 	ACTCTXW actctx = { sizeof(actctx) };
115     actctx.hModule = hInstance;
116     actctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID| ACTCTX_FLAG_HMODULE_VALID;
117     actctx.lpResourceName = MAKEINTRESOURCEW(500);
118 	hActCtx = CreateActCtxW(&actctx);
119 
120 	hico = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_WIN32PROJECT1));
121 	hbmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_BITMAP1));
122 
123     scPos.x = 0;
124     scPos.y = 0;
125 
126     hbrNULL = (HBRUSH)GetStockObject (NULL_BRUSH);
127     hbrRed = CreateSolidBrush(0x00000FF);
128     hbrGreen = CreateSolidBrush(0x0000FF00);
129     hbrBlue = CreateSolidBrush(0x00FF0000);
130     hbrCyan = CreateSolidBrush(0x00FFFF00);
131     hbrYellow = CreateSolidBrush(0x0000FFFF);
132 
133     hbrCtlColorStatic = hbrRed;
134     hbrCtlColorBtn = hbrCyan;
135     hbrPrintClientClear = hbrYellow;
136     hbrErase = hbrGreen;
137 
138     bSkipErase = FALSE;
139     bSkipPaint = FALSE;
140 
141 	RegisterMyClass(hInstance);
142 
143 	HWND hWnd = CreateWindowExW(WS_EX_CLIENTEDGE, L"ButtonTests", L"Button tests", WS_OVERLAPPEDWINDOW| WS_HSCROLL| WS_VSCROLL,
144 		CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
145 
146 	CreateWnd(hWnd, L"Static", L"no images", 0, -1, 0);
147 	CreateWnd(hWnd, L"Static", L"with BM_SETIMAGE", 0, -1, 1);
148 	CreateWnd(hWnd, L"Static", L"with BM_SETIMAGE", 0, -1, 2);
149 	CreateWnd(hWnd, L"Static", L"with BM_SETIMAGE and BS_BITMAP", 0, -1, 3);
150 	CreateWnd(hWnd, L"Static", L"with BM_SETIMAGE and BS_ICON", 0, -1, 4);
151 
152 	CreateWnd(hWnd, L"Static", L"Button V5", 0, 0, -1);
153 	CreateButtonSet(hWnd, &hwnd[0],  0, 0,  BS_PUSHBUTTON);
154 	CreateButtonSet(hWnd, &hwnd[5],  1, 0,  BS_DEFPUSHBUTTON);
155     CreateButtonSet(hWnd, &hwnd[10], 0, 5,  BS_PUSHBUTTON|WS_DISABLED);
156 	CreateButtonSet(hWnd, &hwnd[15], 1, 5,  BS_GROUPBOX);
157 	CreateButtonSet(hWnd, &hwnd[20], 0, 10, BS_CHECKBOX);
158 	CreateButtonSet(hWnd, &hwnd[25], 1, 10, BS_RADIOBUTTON);
159 
160 	bActivated = ActivateActCtx(hActCtx, &cookie);
161     LoadLibraryW(L"comctl32.dll");
162 
163     himl = ImageList_LoadImageW(hInstance, MAKEINTRESOURCEW(IDB_BITMAP2), 16, 0, CLR_DEFAULT, IMAGE_BITMAP, LR_CREATEDIBSECTION);
164     BUTTON_IMAGELIST btniml = {himl, {1,1,1,1}, BUTTON_IMAGELIST_ALIGN_LEFT};
165 
166 	CreateWnd(hWnd, L"Static", L"Button V6 without themes", 0, 2, -1);
167 	CreateButtonSet(hWnd, &hwnd[30], 2, 0,  BS_PUSHBUTTON);
168 	CreateButtonSet(hWnd, &hwnd[35], 3, 0,  BS_DEFPUSHBUTTON);
169     CreateButtonSet(hWnd, &hwnd[40], 2, 5,  BS_PUSHBUTTON|WS_DISABLED);
170 	CreateButtonSet(hWnd, &hwnd[55], 3, 5,  BS_GROUPBOX);
171 	CreateButtonSet(hWnd, &hwnd[50], 2, 10, BS_CHECKBOX);
172 	CreateButtonSet(hWnd, &hwnd[55], 3, 10, BS_RADIOBUTTON);
173 
174 	CreateWnd(hWnd, L"Static", L"Button V6 with imagelist and no themes", 0, 4, -1);
175 	CreateButtonSet(hWnd, &hwnd[60], 4, 0,  BS_PUSHBUTTON);
176 	CreateButtonSet(hWnd, &hwnd[65], 5, 0,  BS_DEFPUSHBUTTON);
177 	CreateButtonSet(hWnd, &hwnd[70], 4, 5,  BS_PUSHBUTTON|WS_DISABLED);
178 	CreateButtonSet(hWnd, &hwnd[75], 5, 5,  BS_GROUPBOX);
179 	CreateButtonSet(hWnd, &hwnd[80], 4, 10, BS_CHECKBOX);
180 	CreateButtonSet(hWnd, &hwnd[85], 5, 10, BS_RADIOBUTTON);
181 
182 	for (int i = 30; i < 90; i++)
183 		SetWindowTheme(hwnd[i], L"", L"");
184 
185 	for (int i = 60; i< 90; i++)
186 		SendMessageW(hwnd[i], BCM_SETIMAGELIST, 0, (LPARAM)&btniml);
187 
188 	CreateWnd(hWnd, L"Static", L"Button V6 with themes and imagelist", 0, 6, -1);
189 	CreateButtonSet(hWnd, &hwnd[120], 6, 0,  BS_PUSHBUTTON);
190 	CreateButtonSet(hWnd, &hwnd[125], 7, 0,  BS_DEFPUSHBUTTON);
191     CreateButtonSet(hWnd, &hwnd[130], 6, 5,  BS_PUSHBUTTON|WS_DISABLED);
192 	CreateButtonSet(hWnd, &hwnd[135], 7, 5,  BS_GROUPBOX);
193 	CreateButtonSet(hWnd, &hwnd[140], 6, 10, BS_CHECKBOX);
194 	CreateButtonSet(hWnd, &hwnd[145], 7, 10, BS_RADIOBUTTON);
195 
196 	CreateWnd(hWnd, L"Static", L"Button V6 with themes", 0, 8, -1);
197 	CreateButtonSet(hWnd, &hwnd[90],  8, 0,  BS_PUSHBUTTON);
198 	CreateButtonSet(hWnd, &hwnd[95],  9, 0,  BS_DEFPUSHBUTTON);
199     CreateButtonSet(hWnd, &hwnd[100], 8, 5,  BS_PUSHBUTTON|WS_DISABLED);
200 	CreateButtonSet(hWnd, &hwnd[105], 9, 5,  BS_GROUPBOX);
201 	CreateButtonSet(hWnd, &hwnd[110], 8, 10, BS_CHECKBOX);
202 	CreateButtonSet(hWnd, &hwnd[115], 9, 10, BS_RADIOBUTTON);
203 
204 	for (int i = 120; i< 150; i++)
205 		SendMessageW(hwnd[i], BCM_SETIMAGELIST, 0, (LPARAM)&btniml);
206 
207 	if (bActivated) DeactivateActCtx(0, cookie);
208 
209     SCROLLINFO vsi = {sizeof(SCROLLINFO), SIF_ALL, 0, 2 * TOP_MARGIN + 10 * (Y_GAP + Y_HEIGHT), Y_HEIGHT, 0, 0};
210     SCROLLINFO hsi = {sizeof(SCROLLINFO), SIF_ALL, 0, 2 * LEFT_MARGIN + 13 * (X_GAP + X_WIDTH), X_WIDTH, 0, 0};
211 
212     SetScrollInfo(hWnd, SB_HORZ, &hsi, FALSE);
213     SetScrollInfo(hWnd, SB_VERT, &vsi, FALSE);
214 
215     ShowScrollBar(hWnd, SB_HORZ, TRUE);
216     ShowScrollBar(hWnd, SB_VERT, TRUE);
217 
218 	ShowWindow(hWnd, nCmdShow);
219 	UpdateWindow(hWnd);
220 
221     MSG msg;
222     while (GetMessage(&msg, NULL, 0, 0))
223     {
224         TranslateMessage(&msg);
225         DispatchMessage(&msg);
226     }
227 
228     return (int) msg.wParam;
229 }
230 
231 static VOID
232 OnScroll(HWND hwnd, INT nBar, WORD sbCode)
233 {
234     RECT rect;
235 
236     SCROLLINFO sInfo;
237     INT oldPos, Maximum;
238     PLONG pOriginXY;
239 
240     //ASSERT(nBar == SB_HORZ || nBar == SB_VERT);
241 
242     GetClientRect(hwnd, &rect);
243 
244     if (nBar == SB_HORZ)
245     {
246         Maximum =1000;//pData->cxMin - (rect.right-rect.left) /* pData->cxOld */;
247         pOriginXY = &scPos.x;
248     }
249     else // if (nBar == SB_VERT)
250     {
251         Maximum = 1000;//pData->cyMin - (rect.bottom-rect.top) /* pData->cyOld */;
252         pOriginXY = &scPos.y;
253     }
254 
255     /* Set scrollbar sizes */
256     sInfo.cbSize = sizeof(sInfo);
257     sInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_TRACKPOS;
258 
259     if (!GetScrollInfo(hwnd, nBar, &sInfo))
260         return;
261 
262     oldPos = sInfo.nPos;
263 
264     switch (sbCode)
265     {
266         case SB_LINEUP:   // SB_LINELEFT:
267             sInfo.nPos--;
268             break;
269 
270         case SB_LINEDOWN: // SB_LINERIGHT:
271             sInfo.nPos++;
272             break;
273 
274         case SB_PAGEUP:   // SB_PAGELEFT:
275             sInfo.nPos -= sInfo.nPage;
276             break;
277 
278         case SB_PAGEDOWN: // SB_PAGERIGHT:
279             sInfo.nPos += sInfo.nPage;
280             break;
281 
282         case SB_THUMBTRACK:
283             sInfo.nPos = sInfo.nTrackPos;
284             break;
285 
286         case SB_THUMBPOSITION:
287             sInfo.nPos = sInfo.nTrackPos;
288             break;
289 
290         case SB_TOP:    // SB_LEFT:
291             sInfo.nPos = sInfo.nMin;
292             break;
293 
294         case SB_BOTTOM: // SB_RIGHT:
295             sInfo.nPos = sInfo.nMax;
296             break;
297 
298         default:
299             break;
300     }
301 
302     sInfo.nPos = min(max(sInfo.nPos, 0), Maximum);
303 
304     if (oldPos != sInfo.nPos)
305     {
306         POINT scOldPos = scPos;
307 
308         /* We now modify scPos */
309         *pOriginXY = sInfo.nPos;
310 
311         ScrollWindowEx(hwnd,
312                        (scOldPos.x - scPos.x),
313                        (scOldPos.y - scPos.y),
314                        NULL,
315                        NULL,
316                        NULL,
317                        NULL,
318                        SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN);
319 
320         sInfo.fMask = SIF_POS;
321         SetScrollInfo(hwnd, nBar, &sInfo, TRUE);
322     }
323 }
324 
325 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
326 {
327     RECT rc = {0,0,5000,5000};
328     switch (message)
329     {
330     case WM_DESTROY:
331         PostQuitMessage(0);
332         break;
333     case WM_CTLCOLORSTATIC:
334         return (LRESULT)hbrCtlColorStatic;
335     case WM_CTLCOLORBTN:
336         return (LRESULT)hbrCtlColorBtn;
337     case WM_ERASEBKGND:
338         FillRect((HDC)wParam, &rc, hbrErase);
339         return TRUE;
340     case WM_PRINTCLIENT:
341         FillRect((HDC)wParam, &rc, hbrPrintClientClear);
342         break;
343     case WM_HSCROLL:
344         OnScroll(hWnd, SB_HORZ, LOWORD(wParam));
345         break;
346     case WM_VSCROLL:
347         OnScroll(hWnd, SB_VERT, LOWORD(wParam));
348         break;
349     case WM_DRAWITEM :
350     {
351         DRAWITEMSTRUCT* di = (DRAWITEMSTRUCT*)lParam;
352         INT oldBkMode;
353         INT state = (di->itemState == ODS_SELECTED) ? DFCS_BUTTONPUSH|DFCS_PUSHED : DFCS_BUTTONPUSH;
354         DrawFrameControl( di->hDC, &di->rcItem, DFC_BUTTON, state );
355         oldBkMode = SetBkMode(di->hDC, TRANSPARENT);
356         DrawTextW(di->hDC, L"Ownder drawn text", -1, &di->rcItem, DT_VCENTER | DT_CENTER);
357         SetBkMode(di->hDC, oldBkMode);
358         break;
359     }
360     case WM_NOTIFY:
361     {
362         NMHDR* phdr = (NMHDR*)lParam;
363         if (phdr->code == NM_CUSTOMDRAW)
364         {
365             LPNMCUSTOMDRAW lpNMCustomDraw = (LPNMCUSTOMDRAW) lParam;
366             if (lpNMCustomDraw->dwDrawStage == CDDS_PREERASE && bSkipErase)
367                 return CDRF_SKIPDEFAULT;
368             else if (lpNMCustomDraw->dwDrawStage == CDDS_PREPAINT && bSkipPaint)
369                 return CDRF_SKIPDEFAULT;
370             return CDRF_DODEFAULT;
371         }
372     }
373     case WM_COMMAND:
374     {
375         UINT id = LOWORD(wParam);
376         switch(id)
377         {
378             case IDM_NULL_WIN:   hbrErase = hbrNULL;  break;
379             case IDM_RED_WIN:    hbrErase = hbrRed;  break;
380             case IDM_GREEN_WIN:  hbrErase = hbrGreen;  break;
381             case IDM_BLUE_WIN:   hbrErase = hbrBlue;  break;
382             case IDM_YELLOW_WIN: hbrErase = hbrYellow;  break;
383             case IDM_CYAN_WIN:   hbrErase = hbrCyan;  break;
384 
385             case IDM_NULL_STATIC:   hbrCtlColorStatic = hbrNULL;  break;
386             case IDM_RED_STATIC:    hbrCtlColorStatic = hbrRed;  break;
387             case IDM_GREEN_STATIC:  hbrCtlColorStatic = hbrGreen;  break;
388             case IDM_BLUE_STATIC:   hbrCtlColorStatic = hbrBlue;  break;
389             case IDM_YELLOW_STATIC: hbrCtlColorStatic = hbrYellow;  break;
390             case IDM_CYAN_STATIC:   hbrCtlColorStatic = hbrCyan;  break;
391 
392             case IDM_NULL_BTN:      hbrCtlColorBtn = hbrNULL;  break;
393             case IDM_RED_BTN:       hbrCtlColorBtn = hbrRed;  break;
394             case IDM_GREEN_BTN:     hbrCtlColorBtn = hbrGreen;  break;
395             case IDM_BLUE_BTN:      hbrCtlColorBtn = hbrBlue;  break;
396             case IDM_YELLOW_BTN:    hbrCtlColorBtn = hbrYellow;  break;
397             case IDM_CYAN_BTN:      hbrCtlColorBtn = hbrCyan;  break;
398 
399             case IDM_NULL_PRINTCLNT:    hbrPrintClientClear = hbrNULL;  break;
400             case IDM_RED_PRINTCLNT:     hbrPrintClientClear = hbrRed;  break;
401             case IDM_GREEN_PRINTCLNT:   hbrPrintClientClear = hbrGreen;  break;
402             case IDM_BLUE_PRINTCLNT:    hbrPrintClientClear = hbrBlue;  break;
403             case IDM_YELLOW_PRINTCLNT:  hbrPrintClientClear = hbrYellow;  break;
404             case IDM_CYAN_PRINTCLNT:    hbrPrintClientClear = hbrCyan;  break;
405 
406             case IDM_SKIP_ERASE:    bSkipErase = !bSkipErase; break;
407             case IDM_SKIP_PAINT:    bSkipPaint = !bSkipPaint; break;
408             default:
409                 return 0;
410         }
411 
412         InvalidateRect(hWnd, NULL, TRUE);
413         break;
414     }
415     default:
416         return DefWindowProc(hWnd, message, wParam, lParam);
417     }
418     return 0;
419 }
420