Sync to trunk head(r38096)
[reactos.git] / rostests / winetests / user32 / combo.c
1 /* Unit test suite for combo boxes.
2 *
3 * Copyright 2007 Mikolaj Zalewski
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include <assert.h>
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #define STRICT
25 #define WIN32_LEAN_AND_MEAN
26 #include <windows.h>
27
28 #include "wine/test.h"
29
30 #define COMBO_ID 1995
31
32 static HWND hMainWnd;
33
34 #define expect_eq(expr, value, type, fmt); { type val = expr; ok(val == (value), #expr " expected " #fmt " got " #fmt "\n", (value), val); }
35 #define expect_rect(r, _left, _top, _right, _bottom) ok(r.left == _left && r.top == _top && \
36 r.bottom == _bottom && r.right == _right, "Invalid rect (%d,%d) (%d,%d) vs (%d,%d) (%d,%d)\n", \
37 r.left, r.top, r.right, r.bottom, _left, _top, _right, _bottom);
38
39 static HWND build_combo(DWORD style)
40 {
41 return CreateWindow("ComboBox", "Combo", WS_VISIBLE|WS_CHILD|style, 5, 5, 100, 100, hMainWnd, (HMENU)COMBO_ID, NULL, 0);
42 }
43
44 static int font_height(HFONT hFont)
45 {
46 TEXTMETRIC tm;
47 HFONT hFontOld;
48 HDC hDC;
49
50 hDC = CreateCompatibleDC(NULL);
51 hFontOld = SelectObject(hDC, hFont);
52 GetTextMetrics(hDC, &tm);
53 SelectObject(hDC, hFontOld);
54 DeleteDC(hDC);
55
56 return tm.tmHeight;
57 }
58
59 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
60 {
61 return 0;
62 }
63
64 static int is_font_installed(const char *name)
65 {
66 HDC hdc = GetDC(NULL);
67 BOOL ret = !EnumFontFamilies(hdc, name, is_font_installed_proc, 0);
68 ReleaseDC(NULL, hdc);
69 return ret;
70 }
71
72 static void test_setitemheight(DWORD style)
73 {
74 HWND hCombo = build_combo(style);
75 RECT r;
76 int i;
77
78 trace("Style %x\n", style);
79 GetClientRect(hCombo, &r);
80 expect_rect(r, 0, 0, 100, 24);
81 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
82 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
83 todo_wine expect_rect(r, 5, 5, 105, 105);
84
85 for (i = 1; i < 30; i++)
86 {
87 SendMessage(hCombo, CB_SETITEMHEIGHT, -1, i);
88 GetClientRect(hCombo, &r);
89 expect_eq(r.bottom - r.top, i + 6, int, "%d");
90 }
91
92 DestroyWindow(hCombo);
93 }
94
95 static void test_setfont(DWORD style)
96 {
97 HWND hCombo = build_combo(style);
98 HFONT hFont1 = CreateFont(10, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett");
99 HFONT hFont2 = CreateFont(8, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett");
100 RECT r;
101 int i;
102
103 trace("Style %x\n", style);
104 GetClientRect(hCombo, &r);
105 expect_rect(r, 0, 0, 100, 24);
106 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
107 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
108 todo_wine expect_rect(r, 5, 5, 105, 105);
109
110 if (!is_font_installed("Marlett"))
111 {
112 skip("Marlett font not available\n");
113 DestroyWindow(hCombo);
114 DeleteObject(hFont1);
115 DeleteObject(hFont2);
116 return;
117 }
118
119 if (font_height(hFont1) == 10 && font_height(hFont2) == 8)
120 {
121 SendMessage(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE);
122 GetClientRect(hCombo, &r);
123 expect_rect(r, 0, 0, 100, 18);
124 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
125 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
126 todo_wine expect_rect(r, 5, 5, 105, 99);
127
128 SendMessage(hCombo, WM_SETFONT, (WPARAM)hFont2, FALSE);
129 GetClientRect(hCombo, &r);
130 expect_rect(r, 0, 0, 100, 16);
131 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
132 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
133 todo_wine expect_rect(r, 5, 5, 105, 97);
134
135 SendMessage(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE);
136 GetClientRect(hCombo, &r);
137 expect_rect(r, 0, 0, 100, 18);
138 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
139 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
140 todo_wine expect_rect(r, 5, 5, 105, 99);
141 }
142 else
143 skip("Invalid Marlett font heights\n");
144
145 for (i = 1; i < 30; i++)
146 {
147 HFONT hFont = CreateFont(i, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett");
148 int height = font_height(hFont);
149
150 SendMessage(hCombo, WM_SETFONT, (WPARAM)hFont, FALSE);
151 GetClientRect(hCombo, &r);
152 expect_eq(r.bottom - r.top, height + 8, int, "%d");
153 SendMessage(hCombo, WM_SETFONT, 0, FALSE);
154 DeleteObject(hFont);
155 }
156
157 DestroyWindow(hCombo);
158 DeleteObject(hFont1);
159 DeleteObject(hFont2);
160 }
161
162 static LRESULT (CALLBACK *old_parent_proc)(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
163 static LPCSTR expected_edit_text;
164 static LPCSTR expected_list_text;
165 static BOOL selchange_fired;
166
167 static LRESULT CALLBACK parent_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
168 {
169 switch (msg)
170 {
171 case WM_COMMAND:
172 switch (wparam)
173 {
174 case MAKEWPARAM(COMBO_ID, CBN_SELCHANGE):
175 {
176 HWND hCombo = (HWND)lparam;
177 int idx;
178 char list[20], edit[20];
179
180 memset(list, 0, sizeof(list));
181 memset(edit, 0, sizeof(edit));
182
183 idx = SendMessage(hCombo, CB_GETCURSEL, 0, 0);
184 SendMessage(hCombo, CB_GETLBTEXT, idx, (LPARAM)list);
185 SendMessage(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
186
187 ok(!strcmp(edit, expected_edit_text), "edit: got %s, expected %s\n",
188 edit, expected_edit_text);
189 ok(!strcmp(list, expected_list_text), "list: got %s, expected %s\n",
190 list, expected_list_text);
191
192 selchange_fired = TRUE;
193 }
194 break;
195 }
196 break;
197 }
198
199 return CallWindowProc(old_parent_proc, hwnd, msg, wparam, lparam);
200 }
201
202 static void test_selection(DWORD style, const char * const text[],
203 const int *edit, const int *list)
204 {
205 INT idx;
206 HWND hCombo;
207
208 hCombo = build_combo(style);
209
210 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)text[0]);
211 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)text[1]);
212 SendMessage(hCombo, CB_SETCURSEL, -1, 0);
213
214 old_parent_proc = (void *)SetWindowLongPtr(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)parent_wnd_proc);
215
216 idx = SendMessage(hCombo, CB_GETCURSEL, 0, 0);
217 ok(idx == -1, "expected selection -1, got %d\n", idx);
218
219 /* keyboard navigation */
220
221 expected_list_text = text[list[0]];
222 expected_edit_text = text[edit[0]];
223 selchange_fired = FALSE;
224 SendMessage(hCombo, WM_KEYDOWN, VK_DOWN, 0);
225 ok(selchange_fired, "CBN_SELCHANGE not sent!\n");
226
227 expected_list_text = text[list[1]];
228 expected_edit_text = text[edit[1]];
229 selchange_fired = FALSE;
230 SendMessage(hCombo, WM_KEYDOWN, VK_DOWN, 0);
231 ok(selchange_fired, "CBN_SELCHANGE not sent!\n");
232
233 expected_list_text = text[list[2]];
234 expected_edit_text = text[edit[2]];
235 selchange_fired = FALSE;
236 SendMessage(hCombo, WM_KEYDOWN, VK_UP, 0);
237 ok(selchange_fired, "CBN_SELCHANGE not sent!\n");
238
239 /* programmatic navigation */
240
241 expected_list_text = text[list[3]];
242 expected_edit_text = text[edit[3]];
243 selchange_fired = FALSE;
244 SendMessage(hCombo, CB_SETCURSEL, list[3], 0);
245 ok(!selchange_fired, "CBN_SELCHANGE sent!\n");
246
247 expected_list_text = text[list[4]];
248 expected_edit_text = text[edit[4]];
249 selchange_fired = FALSE;
250 SendMessage(hCombo, CB_SETCURSEL, list[4], 0);
251 ok(!selchange_fired, "CBN_SELCHANGE sent!\n");
252
253 SetWindowLongPtr(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)old_parent_proc);
254 DestroyWindow(hCombo);
255 }
256
257 static void test_CBN_SELCHANGE(void)
258 {
259 static const char * const text[] = { "alpha", "beta", "" };
260 static const int sel_1[] = { 2, 0, 1, 0, 1 };
261 static const int sel_2[] = { 0, 1, 0, 0, 1 };
262
263 test_selection(CBS_SIMPLE, text, sel_1, sel_2);
264 test_selection(CBS_DROPDOWN, text, sel_1, sel_2);
265 test_selection(CBS_DROPDOWNLIST, text, sel_2, sel_2);
266 }
267
268 START_TEST(combo)
269 {
270 hMainWnd = CreateWindow("static", "Test", WS_OVERLAPPEDWINDOW, 10, 10, 300, 300, NULL, NULL, NULL, 0);
271 ShowWindow(hMainWnd, SW_SHOW);
272
273 test_setfont(CBS_DROPDOWN);
274 test_setfont(CBS_DROPDOWNLIST);
275 test_setitemheight(CBS_DROPDOWN);
276 test_setitemheight(CBS_DROPDOWNLIST);
277 test_CBN_SELCHANGE();
278
279 DestroyWindow(hMainWnd);
280 }