Add support for drawing menus in "flat" style.
[wine] / dlls / user / tests / listbox.c
1 /* Unit test suite for list boxes.
2  *
3  * Copyright 2003 Ferenc Wagner
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include <assert.h>
21 #include <windows.h>
22
23 #include "wine/test.h"
24
25 #ifdef VISIBLE
26 #define WAIT Sleep (1000)
27 #define REDRAW RedrawWindow (handle, NULL, 0, RDW_UPDATENOW)
28 #else
29 #define WAIT
30 #define REDRAW
31 #endif
32
33 static const char *strings[4] = {
34   "First added",
35   "Second added",
36   "Third added",
37   "Fourth added which is very long because at some time we only had a 256 byte character buffer and that was overflowing in one of those applications that had a common dialog file open box and tried to add a 300 characters long custom filter string which of course the code did not like and crashed. Just make sure this string is longer than 256 characters."
38 };
39
40 static HWND
41 create_listbox (DWORD add_style)
42 {
43   HWND handle=CreateWindow ("LISTBOX", "TestList",
44                             (LBS_STANDARD & ~LBS_SORT) | add_style,
45                             0, 0, 100, 100,
46                             NULL, NULL, NULL, 0);
47
48   assert (handle);
49   SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) strings[0]);
50   SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) strings[1]);
51   SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) strings[2]);
52   SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) strings[3]);
53
54 #ifdef VISIBLE
55   ShowWindow (handle, SW_SHOW);
56 #endif
57   REDRAW;
58
59   return handle;
60 }
61
62 struct listbox_prop {
63   DWORD add_style;
64 };
65
66 struct listbox_stat {
67   int selected, anchor, caret, selcount;
68 };
69
70 struct listbox_test {
71   struct listbox_prop prop;
72   struct listbox_stat  init,  init_todo;
73   struct listbox_stat click, click_todo;
74   struct listbox_stat  step,  step_todo;
75   struct listbox_stat   sel,   sel_todo;
76 };
77
78 static void
79 listbox_query (HWND handle, struct listbox_stat *results)
80 {
81   results->selected = SendMessage (handle, LB_GETCURSEL, 0, 0);
82   results->anchor   = SendMessage (handle, LB_GETANCHORINDEX, 0, 0);
83   results->caret    = SendMessage (handle, LB_GETCARETINDEX, 0, 0);
84   results->selcount = SendMessage (handle, LB_GETSELCOUNT, 0, 0);
85 }
86
87 static void
88 buttonpress (HWND handle, WORD x, WORD y)
89 {
90   LPARAM lp=x+(y<<16);
91
92   WAIT;
93   SendMessage (handle, WM_LBUTTONDOWN, (WPARAM) MK_LBUTTON, lp);
94   SendMessage (handle, WM_LBUTTONUP  , (WPARAM) 0         , lp);
95   REDRAW;
96 }
97
98 static void
99 keypress (HWND handle, WPARAM keycode, BYTE scancode, BOOL extended)
100 {
101   LPARAM lp=1+(scancode<<16)+(extended?KEYEVENTF_EXTENDEDKEY:0);
102
103   WAIT;
104   SendMessage (handle, WM_KEYDOWN, keycode, lp);
105   SendMessage (handle, WM_KEYUP  , keycode, lp | 0xc000000);
106   REDRAW;
107 }
108
109 #define listbox_field_ok(t, s, f, got) \
110   ok (t.s.f==got.f, "style %#x, step " #s ", field " #f \
111       ": expected %d, got %d\n", (unsigned int)t.prop.add_style, \
112       t.s.f, got.f)
113
114 #define listbox_todo_field_ok(t, s, f, got) \
115   if (t.s##_todo.f) todo_wine { listbox_field_ok(t, s, f, got); } \
116   else listbox_field_ok(t, s, f, got)
117
118 #define listbox_ok(t, s, got) \
119   listbox_todo_field_ok(t, s, selected, got); \
120   listbox_todo_field_ok(t, s, anchor, got); \
121   listbox_todo_field_ok(t, s, caret, got); \
122   listbox_todo_field_ok(t, s, selcount, got)
123
124 static void
125 check (const struct listbox_test test)
126 {
127   struct listbox_stat answer;
128   HWND hLB=create_listbox (test.prop.add_style);
129   RECT second_item;
130   int i;
131
132   listbox_query (hLB, &answer);
133   listbox_ok (test, init, answer);
134
135   SendMessage (hLB, LB_GETITEMRECT, (WPARAM) 1, (LPARAM) &second_item);
136   buttonpress(hLB, (WORD)second_item.left, (WORD)second_item.top);
137
138   listbox_query (hLB, &answer);
139   listbox_ok (test, click, answer);
140
141   keypress (hLB, VK_DOWN, 0x50, TRUE);
142
143   listbox_query (hLB, &answer);
144   listbox_ok (test, step, answer);
145
146   DestroyWindow (hLB);
147   hLB=create_listbox (test.prop.add_style);
148
149   SendMessage (hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
150   listbox_query (hLB, &answer);
151   listbox_ok (test, sel, answer);
152
153   for (i=0;i<4;i++) {
154         DWORD size = SendMessage (hLB, LB_GETTEXTLEN, i, 0);
155         CHAR *txt;
156         WCHAR *txtw;
157
158         txt = HeapAlloc (GetProcessHeap(), 0, size+1);
159         SendMessageA(hLB, LB_GETTEXT, i, (LPARAM)txt);
160         ok(!strcmp (txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]);
161
162         txtw = HeapAlloc (GetProcessHeap(), 0, 2*size+2);
163         SendMessageW(hLB, LB_GETTEXT, i, (LPARAM)txtw);
164         WideCharToMultiByte( CP_ACP, 0, txtw, -1, txt, size, NULL, NULL );
165         ok(!strcmp (txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]);
166
167         HeapFree (GetProcessHeap(), 0, txtw);
168         HeapFree (GetProcessHeap(), 0, txt);
169   }
170   
171   WAIT;
172   DestroyWindow (hLB);
173 }
174
175 static void check_item_height(void)
176 {
177     HWND hLB;
178     HDC hdc;
179     HFONT font;
180     TEXTMETRICW tm;
181     INT itemHeight;
182
183     hLB = create_listbox (0);
184     ok ((hdc = GetDCEx( hLB, 0, DCX_CACHE )) != 0, "Can't get hdc\n");
185     ok ((font = GetCurrentObject(hdc, OBJ_FONT)) != 0, "Can't get the current font\n");
186     ok (GetTextMetricsW( hdc, &tm ), "Can't read font metrics\n");
187     ReleaseDC( hLB, hdc);
188
189     ok (SendMessageW(hLB, WM_SETFONT, (WPARAM)font, 0) == 0, "Can't set font\n");
190
191     itemHeight = SendMessageW(hLB, LB_GETITEMHEIGHT, 0, 0);
192     ok (itemHeight == tm.tmHeight, "Item height wrong, got %d, expecting %ld\n", itemHeight, tm.tmHeight);
193
194     DestroyWindow (hLB);
195 }
196
197 START_TEST(listbox)
198 {
199   const struct listbox_test SS =
200 /*   {add_style} */
201     {{0},
202      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0},
203      {     1,      1,      1, LB_ERR}, {0,0,0,0},
204      {     2,      2,      2, LB_ERR}, {0,0,0,0},
205      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0}};
206 /* {selected, anchor,  caret, selcount}{TODO fields} */
207   const struct listbox_test SS_NS =
208     {{LBS_NOSEL},
209      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0},
210      {     1,      1,      1, LB_ERR}, {0,0,0,0},
211      {     2,      2,      2, LB_ERR}, {0,0,0,0},
212      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0}};
213   const struct listbox_test MS =
214     {{LBS_MULTIPLESEL},
215      {     0, LB_ERR,      0,      0}, {0,0,0,0},
216      {     1,      1,      1,      1}, {0,0,0,0},
217      {     2,      1,      2,      1}, {0,0,0,0},
218      {     0, LB_ERR,      0,      2}, {0,0,0,0}};
219   const struct listbox_test MS_NS =
220     {{LBS_MULTIPLESEL | LBS_NOSEL},
221      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0},
222      {     1,      1,      1, LB_ERR}, {0,0,0,0},
223      {     2,      2,      2, LB_ERR}, {0,0,0,0},
224      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0}};
225   const struct listbox_test ES =
226     {{LBS_EXTENDEDSEL},
227      {     0, LB_ERR,      0,      0}, {0,0,0,0},
228      {     1,      1,      1,      1}, {0,0,0,0},
229      {     2,      2,      2,      1}, {0,0,0,0},
230      {     0, LB_ERR,      0,      2}, {0,0,0,0}};
231   const struct listbox_test ES_NS =
232     {{LBS_EXTENDEDSEL | LBS_NOSEL},
233      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0},
234      {     1,      1,      1, LB_ERR}, {0,0,0,0},
235      {     2,      2,      2, LB_ERR}, {0,0,0,0},
236      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0}};
237   const struct listbox_test EMS =
238     {{LBS_EXTENDEDSEL | LBS_MULTIPLESEL},
239      {     0, LB_ERR,      0,      0}, {0,0,0,0},
240      {     1,      1,      1,      1}, {0,0,0,0},
241      {     2,      2,      2,      1}, {0,0,0,0},
242      {     0, LB_ERR,      0,      2}, {0,0,0,0}};
243   const struct listbox_test EMS_NS =
244     {{LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL},
245      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0},
246      {     1,      1,      1, LB_ERR}, {0,0,0,0},
247      {     2,      2,      2, LB_ERR}, {0,0,0,0},
248      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0}};
249
250   trace (" Testing single selection...\n");
251   check (SS);
252   trace (" ... with NOSEL\n");
253   check (SS_NS);
254   trace (" Testing multiple selection...\n");
255   check (MS);
256   trace (" ... with NOSEL\n");
257   check (MS_NS);
258   trace (" Testing extended selection...\n");
259   check (ES);
260   trace (" ... with NOSEL\n");
261   check (ES_NS);
262   trace (" Testing extended and multiple selection...\n");
263   check (EMS);
264   trace (" ... with NOSEL\n");
265   check (EMS_NS);
266
267   check_item_height();
268 }