comctl32/tab: Fix selection change when selected item is deleted.
[wine] / dlls / comctl32 / tests / tab.c
1 /* Unit test suite for tab control.
2  *
3  * Copyright 2003 Vitaliy Margolen
4  * Copyright 2007 Hagop Hagopian
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <assert.h>
22 #include <windows.h>
23 #include <commctrl.h>
24 #include <stdio.h>
25
26 #include "wine/test.h"
27 #include "msg.h"
28
29 #define DEFAULT_MIN_TAB_WIDTH 54
30 #define TAB_PADDING_X 6
31 #define EXTRA_ICON_PADDING 3
32 #define MAX_TABLEN 32
33
34 #define NUM_MSG_SEQUENCES  2
35 #define PARENT_SEQ_INDEX   0
36 #define TAB_SEQ_INDEX      1
37
38 #define expect(expected, got) ok ( expected == got, "Expected %d, got %d\n", expected, got)
39 #define expect_str(expected, got)\
40  ok ( strcmp(expected, got) == 0, "Expected '%s', got '%s'\n", expected, got)
41
42 #define TabWidthPadded(padd_x, num) (DEFAULT_MIN_TAB_WIDTH - (TAB_PADDING_X - (padd_x)) * num)
43
44 #define TabCheckSetSize(hwnd, SetWidth, SetHeight, ExpWidth, ExpHeight, Msg)\
45     SendMessage (hwnd, TCM_SETITEMSIZE, 0,\
46         (LPARAM) MAKELPARAM((SetWidth >= 0) ? SetWidth:0, (SetHeight >= 0) ? SetHeight:0));\
47     if (winetest_interactive) RedrawWindow (hwnd, NULL, 0, RDW_UPDATENOW);\
48     CheckSize(hwnd, ExpWidth, ExpHeight, Msg);
49
50 #define CheckSize(hwnd,width,height,msg)\
51     SendMessage (hwnd, TCM_GETITEMRECT, 0, (LPARAM) &rTab);\
52     if ((width  >= 0) && (height < 0))\
53         ok (width  == rTab.right  - rTab.left, "%s: Expected width [%d] got [%d]\n",\
54         msg, (int)width,  rTab.right  - rTab.left);\
55     else if ((height >= 0) && (width  < 0))\
56         ok (height == rTab.bottom - rTab.top,  "%s: Expected height [%d] got [%d]\n",\
57         msg, (int)height, rTab.bottom - rTab.top);\
58     else\
59         ok ((width  == rTab.right  - rTab.left) &&\
60             (height == rTab.bottom - rTab.top ),\
61             "%s: Expected [%d,%d] got [%d,%d]\n", msg, (int)width, (int)height,\
62             rTab.right - rTab.left, rTab.bottom - rTab.top);
63
64 static HFONT hFont = 0;
65
66 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
67
68 static const struct message create_parent_wnd_seq[] = {
69     { WM_GETMINMAXINFO, sent },
70     { WM_NCCREATE, sent },
71     { WM_NCCALCSIZE, sent|wparam, 0 },
72     { WM_CREATE, sent },
73     { WM_SHOWWINDOW, sent|wparam, 1 },
74     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
75     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
76     { WM_ACTIVATEAPP, sent|wparam, 1 },
77     { WM_NCACTIVATE, sent|wparam, 1 },
78     { WM_ACTIVATE, sent|wparam, 1 },
79     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
80     { WM_IME_NOTIFY, sent|defwinproc|optional },
81     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
82     /* Win9x adds SWP_NOZORDER below */
83     { WM_WINDOWPOSCHANGED, sent},
84     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
85     { WM_SIZE, sent },
86     { WM_MOVE, sent },
87     { 0 }
88 };
89
90 static const struct message add_tab_to_parent[] = {
91     { TCM_INSERTITEMA, sent },
92     { TCM_INSERTITEMA, sent|optional },
93     { WM_NOTIFYFORMAT, sent|defwinproc },
94     { WM_QUERYUISTATE, sent|wparam|lparam|defwinproc|optional, 0, 0 },
95     { WM_PARENTNOTIFY, sent|defwinproc },
96     { TCM_INSERTITEMA, sent },
97     { TCM_INSERTITEMA, sent },
98     { TCM_INSERTITEMA, sent },
99     { TCM_INSERTITEMA, sent|optional },
100     { 0 }
101 };
102
103 static const struct message add_tab_to_parent_interactive[] = {
104     { TCM_INSERTITEMA, sent },
105     { TCM_INSERTITEMA, sent },
106     { WM_NOTIFYFORMAT, sent|defwinproc },
107     { WM_QUERYUISTATE, sent|wparam|lparam|defwinproc, 0, 0 },
108     { WM_PARENTNOTIFY, sent|defwinproc },
109     { TCM_INSERTITEMA, sent },
110     { TCM_INSERTITEMA, sent },
111     { TCM_INSERTITEMA, sent },
112     { WM_SHOWWINDOW, sent},
113     { WM_WINDOWPOSCHANGING, sent},
114     { WM_WINDOWPOSCHANGING, sent},
115     { WM_NCACTIVATE, sent},
116     { WM_ACTIVATE, sent},
117     { WM_IME_SETCONTEXT, sent|defwinproc|optional},
118     { WM_IME_NOTIFY, sent|defwinproc|optional},
119     { WM_SETFOCUS, sent|defwinproc},
120     { WM_WINDOWPOSCHANGED, sent},
121     { WM_SIZE, sent},
122     { WM_MOVE, sent},
123     { 0 }
124 };
125
126 static const struct message add_tab_control_parent_seq[] = {
127     { WM_NOTIFYFORMAT, sent },
128     { WM_QUERYUISTATE, sent|wparam|lparam|optional, 0, 0 },
129     { 0 }
130 };
131
132 static const struct message add_tab_control_parent_seq_interactive[] = {
133     { WM_NOTIFYFORMAT, sent },
134     { WM_QUERYUISTATE, sent|wparam|lparam, 0, 0 },
135     { WM_WINDOWPOSCHANGING, sent|optional},
136     { WM_NCACTIVATE, sent},
137     { WM_ACTIVATE, sent},
138     { WM_WINDOWPOSCHANGING, sent|optional},
139     { WM_KILLFOCUS, sent},
140     { WM_IME_SETCONTEXT, sent|optional},
141     { WM_IME_NOTIFY, sent|optional},
142     { 0 }
143 };
144
145 static const struct message empty_sequence[] = {
146     { 0 }
147 };
148
149 static const struct message set_min_tab_width_seq[] = {
150     { TCM_SETMINTABWIDTH, sent|wparam, 0 },
151     { TCM_SETMINTABWIDTH, sent|wparam, 0 },
152     { 0 }
153 };
154
155 static const struct message get_item_count_seq[] = {
156     { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
157     { 0 }
158 };
159
160 static const struct message get_row_count_seq[] = {
161     { TCM_GETROWCOUNT, sent|wparam|lparam, 0, 0 },
162     { 0 }
163 };
164
165 static const struct message get_item_rect_seq[] = {
166     { TCM_GETITEMRECT, sent },
167     { TCM_GETITEMRECT, sent },
168     { 0 }
169 };
170
171 static const struct message getset_cur_focus_seq[] = {
172     { TCM_SETCURFOCUS, sent|lparam, 0 },
173     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
174     { TCM_SETCURFOCUS, sent|lparam, 0 },
175     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
176     { TCM_SETCURSEL, sent|lparam, 0 },
177     { TCM_SETCURFOCUS, sent|lparam, 0 },
178     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
179     { 0 }
180 };
181
182 static const struct message getset_cur_sel_seq[] = {
183     { TCM_SETCURSEL, sent|lparam, 0 },
184     { TCM_GETCURSEL, sent|wparam|lparam, 0, 0 },
185     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
186     { TCM_SETCURSEL, sent|lparam, 0 },
187     { TCM_GETCURSEL, sent|wparam|lparam, 0, 0 },
188     { TCM_SETCURSEL, sent|lparam, 0 },
189     { TCM_SETCURSEL, sent|lparam, 0 },
190     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
191     { 0 }
192 };
193
194 static const struct message getset_extended_style_seq[] = {
195     { TCM_GETEXTENDEDSTYLE, sent|wparam|lparam, 0, 0 },
196     { TCM_SETEXTENDEDSTYLE, sent },
197     { TCM_GETEXTENDEDSTYLE, sent|wparam|lparam, 0, 0 },
198     { TCM_SETEXTENDEDSTYLE, sent },
199     { TCM_GETEXTENDEDSTYLE, sent|wparam|lparam, 0, 0 },
200     { 0 }
201 };
202
203 static const struct message getset_unicode_format_seq[] = {
204     { CCM_SETUNICODEFORMAT, sent|lparam, 0 },
205     { CCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
206     { CCM_SETUNICODEFORMAT, sent|lparam, 0 },
207     { CCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
208     { CCM_SETUNICODEFORMAT, sent|lparam, 0 },
209     { 0 }
210 };
211
212 static const struct message getset_item_seq[] = {
213     { TCM_SETITEMA, sent },
214     { TCM_GETITEMA, sent },
215     { TCM_GETITEMA, sent },
216     { 0 }
217 };
218
219 static const struct message getset_tooltip_seq[] = {
220     { WM_NOTIFYFORMAT, sent|optional },
221     { WM_QUERYUISTATE, sent|wparam|lparam|optional, 0, 0 },
222     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
223     { WM_NOTIFYFORMAT, sent|optional },
224     { TCM_SETTOOLTIPS, sent|lparam, 0 },
225     { TCM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 },
226     { TCM_SETTOOLTIPS, sent|lparam, 0 },
227     { TCM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 },
228     { 0 }
229 };
230
231 static const struct message getset_tooltip_parent_seq[] = {
232     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
233     { 0 }
234 };
235
236 static const struct message insert_focus_seq[] = {
237     { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
238     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
239     { TCM_INSERTITEM, sent|wparam, 1 },
240     { WM_NOTIFYFORMAT, sent|defwinproc|optional },
241     { WM_QUERYUISTATE, sent|defwinproc|optional },
242     { WM_PARENTNOTIFY, sent|defwinproc|optional },
243     { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
244     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
245     { TCM_INSERTITEM, sent|wparam, 2 },
246     { WM_NOTIFYFORMAT, sent|defwinproc|optional },
247     { WM_QUERYUISTATE, sent|defwinproc|optional, },
248     { WM_PARENTNOTIFY, sent|defwinproc|optional },
249     { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
250     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
251     { TCM_SETCURFOCUS, sent|wparam|lparam, -1, 0 },
252     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
253     { TCM_INSERTITEM, sent|wparam, 3 },
254     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
255     { 0 }
256 };
257
258 static const struct message delete_focus_seq[] = {
259     { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
260     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
261     { TCM_DELETEITEM, sent|wparam|lparam, 1, 0 },
262     { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
263     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
264     { TCM_SETCURFOCUS, sent|wparam|lparam, -1, 0 },
265     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
266     { TCM_DELETEITEM, sent|wparam|lparam, 0, 0 },
267     { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
268     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
269     { 0 }
270 };
271
272
273 static HWND
274 create_tabcontrol (DWORD style, DWORD mask)
275 {
276     HWND handle;
277     TCITEM tcNewTab;
278     static char text1[] = "Tab 1",
279     text2[] = "Wide Tab 2",
280     text3[] = "T 3";
281
282     handle = CreateWindow (
283         WC_TABCONTROLA,
284         "TestTab",
285         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | style,
286         10, 10, 300, 100,
287         NULL, NULL, NULL, 0);
288
289     assert (handle);
290
291     SetWindowLong(handle, GWL_STYLE, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | style);
292     SendMessage (handle, WM_SETFONT, 0, (LPARAM) hFont);
293
294     tcNewTab.mask = mask;
295     tcNewTab.pszText = text1;
296     tcNewTab.iImage = 0;
297     SendMessage (handle, TCM_INSERTITEM, 0, (LPARAM) &tcNewTab);
298     tcNewTab.pszText = text2;
299     tcNewTab.iImage = 1;
300     SendMessage (handle, TCM_INSERTITEM, 1, (LPARAM) &tcNewTab);
301     tcNewTab.pszText = text3;
302     tcNewTab.iImage = 2;
303     SendMessage (handle, TCM_INSERTITEM, 2, (LPARAM) &tcNewTab);
304
305     if (winetest_interactive)
306     {
307         ShowWindow (handle, SW_SHOW);
308         RedrawWindow (handle, NULL, 0, RDW_UPDATENOW);
309         Sleep (1000);
310     }
311
312     return handle;
313 }
314
315 static LRESULT WINAPI parentWindowProcess(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
316 {
317     static LONG defwndproc_counter = 0;
318     LRESULT ret;
319     struct message msg;
320
321     /* do not log painting messages */
322     if (message != WM_PAINT &&
323         message != WM_ERASEBKGND &&
324         message != WM_NCPAINT &&
325         message != WM_NCHITTEST &&
326         message != WM_GETTEXT &&
327         message != WM_GETICON &&
328         message != WM_DEVICECHANGE)
329     {
330         trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
331
332         msg.message = message;
333         msg.flags = sent|wparam|lparam;
334         if (defwndproc_counter) msg.flags |= defwinproc;
335         msg.wParam = wParam;
336         msg.lParam = lParam;
337         add_message(sequences, PARENT_SEQ_INDEX, &msg);
338     }
339
340     defwndproc_counter++;
341     ret = DefWindowProcA(hwnd, message, wParam, lParam);
342     defwndproc_counter--;
343
344     return ret;
345 }
346
347 static BOOL registerParentWindowClass(void)
348 {
349     WNDCLASSA cls;
350
351     cls.style = 0;
352     cls.lpfnWndProc = parentWindowProcess;
353     cls.cbClsExtra = 0;
354     cls.cbWndExtra = 0;
355     cls.hInstance = GetModuleHandleA(NULL);
356     cls.hIcon = 0;
357     cls.hCursor = LoadCursorA(0, IDC_ARROW);
358     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
359     cls.lpszMenuName = NULL;
360     cls.lpszClassName = "Tab test parent class";
361     return RegisterClassA(&cls);
362 }
363
364 static HWND createParentWindow(void)
365 {
366     if (!registerParentWindowClass())
367         return NULL;
368
369     return CreateWindowEx(0, "Tab test parent class",
370                           "Tab test parent window",
371                           WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
372                           WS_MAXIMIZEBOX | WS_VISIBLE,
373                           0, 0, 100, 100,
374                           GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
375 }
376
377 static LRESULT WINAPI tabSubclassProcess(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
378 {
379     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
380     static LONG defwndproc_counter = 0;
381     LRESULT ret;
382     struct message msg;
383
384     /* do not log painting messages */
385     if (message != WM_PAINT &&
386         message != WM_ERASEBKGND &&
387         message != WM_NCPAINT &&
388         message != WM_NCHITTEST &&
389         message != WM_GETTEXT &&
390         message != WM_GETICON &&
391         message != WM_DEVICECHANGE)
392     {
393         trace("tab: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
394
395         msg.message = message;
396         msg.flags = sent|wparam|lparam;
397         if (defwndproc_counter) msg.flags |= defwinproc;
398         msg.wParam = wParam;
399         msg.lParam = lParam;
400         add_message(sequences, TAB_SEQ_INDEX, &msg);
401     }
402
403     defwndproc_counter++;
404     ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
405     defwndproc_counter--;
406
407     return ret;
408 }
409
410 static HWND createFilledTabControl(HWND parent_wnd, DWORD style, DWORD mask, INT nTabs)
411 {
412     HWND tabHandle;
413     TCITEM tcNewTab;
414     WNDPROC oldproc;
415     RECT rect;
416     INT i;
417
418     GetClientRect(parent_wnd, &rect);
419
420     tabHandle = CreateWindow (
421         WC_TABCONTROLA,
422         "TestTab",
423         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | style,
424         0, 0, rect.right, rect.bottom,
425         parent_wnd, NULL, NULL, 0);
426
427     assert(tabHandle);
428
429     oldproc = (WNDPROC)SetWindowLongPtrA(tabHandle, GWLP_WNDPROC, (LONG_PTR)tabSubclassProcess);
430     SetWindowLongPtrA(tabHandle, GWLP_USERDATA, (LONG_PTR)oldproc);
431
432     tcNewTab.mask = mask;
433
434     for (i = 0; i < nTabs; i++)
435     {
436         char tabName[MAX_TABLEN];
437
438         sprintf(tabName, "Tab %d", i+1);
439         tcNewTab.pszText = tabName;
440         tcNewTab.iImage = i;
441         SendMessage (tabHandle, TCM_INSERTITEM, i, (LPARAM) &tcNewTab);
442     }
443
444     if (winetest_interactive)
445     {
446         ShowWindow (tabHandle, SW_SHOW);
447         RedrawWindow (tabHandle, NULL, 0, RDW_UPDATENOW);
448         Sleep (1000);
449     }
450
451     return tabHandle;
452 }
453
454 static HWND create_tooltip (HWND hTab, char toolTipText[])
455 {
456     HWND hwndTT;
457
458     TOOLINFO ti;
459     LPTSTR lptstr = toolTipText;
460     RECT rect;
461
462     /* Creating a tooltip window*/
463     hwndTT = CreateWindowEx(
464         WS_EX_TOPMOST,
465         TOOLTIPS_CLASS,
466         NULL,
467         WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
468         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
469         hTab, NULL, 0, NULL);
470
471     SetWindowPos(
472         hwndTT,
473         HWND_TOPMOST,
474         0, 0, 0, 0,
475         SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
476
477     GetClientRect (hTab, &rect);
478
479     /* Initialize members of toolinfo*/
480     ti.cbSize = sizeof(TOOLINFO);
481     ti.uFlags = TTF_SUBCLASS;
482     ti.hwnd = hTab;
483     ti.hinst = 0;
484     ti.uId = 0;
485     ti.lpszText = lptstr;
486
487     ti.rect = rect;
488
489     /* Add toolinfo structure to the tooltip control */
490     SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) &ti);
491
492     return hwndTT;
493 }
494
495 static void test_tab(INT nMinTabWidth)
496 {
497     HWND hwTab;
498     RECT rTab;
499     HIMAGELIST himl = ImageList_Create(21, 21, ILC_COLOR, 3, 4);
500     SIZE size;
501     HDC hdc;
502     HFONT hOldFont;
503     INT i, dpi, exp;
504
505     hwTab = create_tabcontrol(TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE);
506     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
507     /* Get System default MinTabWidth */
508     if (nMinTabWidth < 0)
509         nMinTabWidth = SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
510
511     hdc = GetDC(hwTab);
512     dpi = GetDeviceCaps(hdc, LOGPIXELSX);
513     hOldFont = SelectObject(hdc, (HFONT)SendMessage(hwTab, WM_GETFONT, 0, 0));
514     GetTextExtentPoint32A(hdc, "Tab 1", strlen("Tab 1"), &size);
515     trace("Tab1 text size: size.cx=%d size.cy=%d\n", size.cx, size.cy);
516     SelectObject(hdc, hOldFont);
517     ReleaseDC(hwTab, hdc);
518
519     trace ("  TCS_FIXEDWIDTH tabs no icon...\n");
520     CheckSize(hwTab, dpi, -1, "default width");
521     TabCheckSetSize(hwTab, 50, 20, 50, 20, "set size");
522     TabCheckSetSize(hwTab, 0, 1, 0, 1, "min size");
523
524     SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
525
526     trace ("  TCS_FIXEDWIDTH tabs with icon...\n");
527     TabCheckSetSize(hwTab, 50, 30, 50, 30, "set size > icon");
528     TabCheckSetSize(hwTab, 20, 20, 25, 20, "set size < icon");
529     TabCheckSetSize(hwTab, 0, 1, 25, 1, "min size");
530
531     DestroyWindow (hwTab);
532
533     hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BUTTONS, TCIF_TEXT|TCIF_IMAGE);
534     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
535
536     hdc = GetDC(hwTab);
537     dpi = GetDeviceCaps(hdc, LOGPIXELSX);
538     ReleaseDC(hwTab, hdc);
539     trace ("  TCS_FIXEDWIDTH buttons no icon...\n");
540     CheckSize(hwTab, dpi, -1, "default width");
541     TabCheckSetSize(hwTab, 20, 20, 20, 20, "set size 1");
542     TabCheckSetSize(hwTab, 10, 50, 10, 50, "set size 2");
543     TabCheckSetSize(hwTab, 0, 1, 0, 1, "min size");
544
545     SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
546
547     trace ("  TCS_FIXEDWIDTH buttons with icon...\n");
548     TabCheckSetSize(hwTab, 50, 30, 50, 30, "set size > icon");
549     TabCheckSetSize(hwTab, 20, 20, 25, 20, "set size < icon");
550     TabCheckSetSize(hwTab, 0, 1, 25, 1, "min size");
551     SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(4,4));
552     TabCheckSetSize(hwTab, 0, 1, 25, 1, "set padding, min size");
553
554     DestroyWindow (hwTab);
555
556     hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BOTTOM, TCIF_TEXT|TCIF_IMAGE);
557     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
558
559     hdc = GetDC(hwTab);
560     dpi = GetDeviceCaps(hdc, LOGPIXELSX);
561     ReleaseDC(hwTab, hdc);
562     trace ("  TCS_FIXEDWIDTH | TCS_BOTTOM tabs...\n");
563     CheckSize(hwTab, dpi, -1, "no icon, default width");
564
565     TabCheckSetSize(hwTab, 20, 20, 20, 20, "no icon, set size 1");
566     TabCheckSetSize(hwTab, 10, 50, 10, 50, "no icon, set size 2");
567     TabCheckSetSize(hwTab, 0, 1, 0, 1, "no icon, min size");
568
569     SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
570
571     TabCheckSetSize(hwTab, 50, 30, 50, 30, "with icon, set size > icon");
572     TabCheckSetSize(hwTab, 20, 20, 25, 20, "with icon, set size < icon");
573     TabCheckSetSize(hwTab, 0, 1, 25, 1, "with icon, min size");
574     SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(4,4));
575     TabCheckSetSize(hwTab, 0, 1, 25, 1, "set padding, min size");
576
577     DestroyWindow (hwTab);
578
579     hwTab = create_tabcontrol(0, TCIF_TEXT|TCIF_IMAGE);
580     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
581
582     trace ("  non fixed width, with text...\n");
583     exp = max(size.cx +TAB_PADDING_X*2, (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth);
584     SendMessage( hwTab, TCM_GETITEMRECT, 0, (LPARAM)&rTab );
585     ok( rTab.right  - rTab.left == exp || broken(rTab.right  - rTab.left == DEFAULT_MIN_TAB_WIDTH),
586         "no icon, default width: Expected width [%d] got [%d]\n", exp, rTab.right - rTab.left );
587
588     for (i=0; i<8; i++)
589     {
590         INT nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 2) : nMinTabWidth;
591
592         SendMessage(hwTab, TCM_SETIMAGELIST, 0, 0);
593         SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(i,i));
594
595         TabCheckSetSize(hwTab, 50, 20, max(size.cx + i*2, nTabWidth), 20, "no icon, set size");
596         TabCheckSetSize(hwTab, 0, 1, max(size.cx + i*2, nTabWidth), 1, "no icon, min size");
597
598         SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
599         nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 3) : nMinTabWidth;
600
601         TabCheckSetSize(hwTab, 50, 30, max(size.cx + 21 + i*3, nTabWidth), 30, "with icon, set size > icon");
602         TabCheckSetSize(hwTab, 20, 20, max(size.cx + 21 + i*3, nTabWidth), 20, "with icon, set size < icon");
603         TabCheckSetSize(hwTab, 0, 1, max(size.cx + 21 + i*3, nTabWidth), 1, "with icon, min size");
604     }
605     DestroyWindow (hwTab);
606
607     hwTab = create_tabcontrol(0, TCIF_IMAGE);
608     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
609
610     trace ("  non fixed width, no text...\n");
611     exp = (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth;
612     SendMessage( hwTab, TCM_GETITEMRECT, 0, (LPARAM)&rTab );
613     ok( rTab.right  - rTab.left == exp || broken(rTab.right  - rTab.left == DEFAULT_MIN_TAB_WIDTH),
614         "no icon, default width: Expected width [%d] got [%d]\n", exp, rTab.right - rTab.left );
615
616     for (i=0; i<8; i++)
617     {
618         INT nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 2) : nMinTabWidth;
619
620         SendMessage(hwTab, TCM_SETIMAGELIST, 0, 0);
621         SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(i,i));
622
623         TabCheckSetSize(hwTab, 50, 20, nTabWidth, 20, "no icon, set size");
624         TabCheckSetSize(hwTab, 0, 1, nTabWidth, 1, "no icon, min size");
625
626         SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
627         if (i > 1 && nMinTabWidth > 0 && nMinTabWidth < DEFAULT_MIN_TAB_WIDTH)
628             nTabWidth += EXTRA_ICON_PADDING *(i-1);
629
630         TabCheckSetSize(hwTab, 50, 30, nTabWidth, 30, "with icon, set size > icon");
631         TabCheckSetSize(hwTab, 20, 20, nTabWidth, 20, "with icon, set size < icon");
632         TabCheckSetSize(hwTab, 0, 1, nTabWidth, 1, "with icon, min size");
633     }
634
635     DestroyWindow (hwTab);
636
637     ImageList_Destroy(himl);
638     DeleteObject(hFont);
639 }
640
641 static void test_curfocus(HWND parent_wnd, INT nTabs)
642 {
643     INT focusIndex;
644     HWND hTab;
645
646     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
647     ok(hTab != NULL, "Failed to create tab control\n");
648
649     flush_sequences(sequences, NUM_MSG_SEQUENCES);
650
651     /* Testing CurFocus with largest appropriate value */
652     SendMessage(hTab, TCM_SETCURFOCUS, nTabs-1, 0);
653     focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
654     expect(nTabs-1, focusIndex);
655
656     /* Testing CurFocus with negative value */
657     SendMessage(hTab, TCM_SETCURFOCUS, -10, 0);
658     focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
659     expect(-1, focusIndex);
660
661     /* Testing CurFocus with value larger than number of tabs */
662     focusIndex = SendMessage(hTab, TCM_SETCURSEL, 1, 0);
663     todo_wine{
664         expect(-1, focusIndex);
665     }
666
667     SendMessage(hTab, TCM_SETCURFOCUS, nTabs+1, 0);
668     focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
669     expect(1, focusIndex);
670
671     ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_focus_seq, "Getset curFoc test sequence", FALSE);
672
673     DestroyWindow(hTab);
674 }
675
676 static void test_cursel(HWND parent_wnd, INT nTabs)
677 {
678     INT selectionIndex;
679     INT focusIndex;
680     TCITEM tcItem;
681     HWND hTab;
682
683     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
684     ok(hTab != NULL, "Failed to create tab control\n");
685
686     flush_sequences(sequences, NUM_MSG_SEQUENCES);
687
688     /* Testing CurSel with largest appropriate value */
689     selectionIndex = SendMessage(hTab, TCM_SETCURSEL, nTabs-1, 0);
690     expect(0, selectionIndex);
691     selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
692     expect(nTabs-1, selectionIndex);
693
694     /* Focus should switch with selection */
695     focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
696     expect(nTabs-1, focusIndex);
697
698     /* Testing CurSel with negative value */
699     SendMessage(hTab, TCM_SETCURSEL, -10, 0);
700     selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
701     expect(-1, selectionIndex);
702
703     /* Testing CurSel with value larger than number of tabs */
704     selectionIndex = SendMessage(hTab, TCM_SETCURSEL, 1, 0);
705     expect(-1, selectionIndex);
706
707     selectionIndex = SendMessage(hTab, TCM_SETCURSEL, nTabs+1, 0);
708     expect(-1, selectionIndex);
709     selectionIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
710     expect(1, selectionIndex);
711
712     ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_sel_seq, "Getset curSel test sequence", FALSE);
713     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset curSel test parent sequence", FALSE);
714
715     /* selected item should have TCIS_BUTTONPRESSED state
716        It doesn't depend on button state */
717     memset(&tcItem, 0, sizeof(TCITEM));
718     tcItem.mask = TCIF_STATE;
719     tcItem.dwStateMask = TCIS_BUTTONPRESSED;
720     selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
721     SendMessage(hTab, TCM_GETITEM, selectionIndex, (LPARAM) &tcItem);
722     ok (tcItem.dwState & TCIS_BUTTONPRESSED || broken(tcItem.dwState == 0), /* older comctl32 */
723         "Selected item should have TCIS_BUTTONPRESSED\n");
724
725     DestroyWindow(hTab);
726 }
727
728 static void test_extendedstyle(HWND parent_wnd, INT nTabs)
729 {
730     DWORD prevExtendedStyle;
731     DWORD extendedStyle;
732     HWND hTab;
733
734     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
735     ok(hTab != NULL, "Failed to create tab control\n");
736
737     flush_sequences(sequences, NUM_MSG_SEQUENCES);
738
739     /* Testing Flat Separators */
740     extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
741     prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_FLATSEPARATORS);
742     expect(extendedStyle, prevExtendedStyle);
743
744     extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
745     expect(TCS_EX_FLATSEPARATORS, extendedStyle);
746
747     /* Testing Register Drop */
748     prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_REGISTERDROP);
749     expect(extendedStyle, prevExtendedStyle);
750
751     extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
752     todo_wine{
753         expect(TCS_EX_REGISTERDROP, extendedStyle);
754     }
755
756     ok_sequence(sequences, TAB_SEQ_INDEX, getset_extended_style_seq, "Getset extendedStyle test sequence", FALSE);
757     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset extendedStyle test parent sequence", FALSE);
758
759     DestroyWindow(hTab);
760 }
761
762 static void test_unicodeformat(HWND parent_wnd, INT nTabs)
763 {
764     INT unicodeFormat;
765     HWND hTab;
766
767     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
768     ok(hTab != NULL, "Failed to create tab control\n");
769
770     flush_sequences(sequences, NUM_MSG_SEQUENCES);
771
772     unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0);
773     todo_wine{
774         expect(0, unicodeFormat);
775     }
776     unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0);
777     expect(1, unicodeFormat);
778
779     unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, FALSE, 0);
780     expect(1, unicodeFormat);
781     unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0);
782     expect(0, unicodeFormat);
783
784     unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0);
785     expect(0, unicodeFormat);
786
787     ok_sequence(sequences, TAB_SEQ_INDEX, getset_unicode_format_seq, "Getset unicodeFormat test sequence", FALSE);
788     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset unicodeFormat test parent sequence", FALSE);
789
790     DestroyWindow(hTab);
791 }
792
793 static void test_getset_item(HWND parent_wnd, INT nTabs)
794 {
795     TCITEM tcItem;
796     DWORD ret;
797     char szText[32] = "New Label";
798     HWND hTab;
799
800     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
801     ok(hTab != NULL, "Failed to create tab control\n");
802
803     /* passing invalid index should result in initialization to zero
804        for members mentioned in mask requested */
805
806     /* valid range here is [0,4] */
807     memset(&tcItem, 0xcc, sizeof(tcItem));
808     tcItem.mask = TCIF_PARAM;
809     ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
810     expect(FALSE, ret);
811     ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam);
812
813     memset(&tcItem, 0xcc, sizeof(tcItem));
814     tcItem.mask = TCIF_IMAGE;
815     ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
816     expect(FALSE, ret);
817     expect(0, tcItem.iImage);
818
819     memset(&tcItem, 0xcc, sizeof(tcItem));
820     tcItem.mask = TCIF_TEXT;
821     tcItem.pszText = szText;
822     szText[0] = 'a';
823     ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
824     expect(FALSE, ret);
825     expect('a', szText[0]);
826
827     memset(&tcItem, 0xcc, sizeof(tcItem));
828     tcItem.mask = TCIF_STATE;
829     tcItem.dwStateMask = 0;
830     tcItem.dwState = TCIS_BUTTONPRESSED;
831     ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
832     expect(FALSE, ret);
833     ok(tcItem.dwState == 0, "Expected zero dwState, got %u\n", tcItem.dwState);
834
835     memset(&tcItem, 0xcc, sizeof(tcItem));
836     tcItem.mask = TCIF_STATE;
837     tcItem.dwStateMask = TCIS_BUTTONPRESSED;
838     tcItem.dwState = TCIS_BUTTONPRESSED;
839     ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
840     expect(FALSE, ret);
841     ok(tcItem.dwState == 0, "Expected zero dwState\n");
842
843     /* check with negative index to be sure */
844     memset(&tcItem, 0xcc, sizeof(tcItem));
845     tcItem.mask = TCIF_PARAM;
846     ret = SendMessage(hTab, TCM_GETITEM, -1, (LPARAM)&tcItem);
847     expect(FALSE, ret);
848     ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam);
849
850     memset(&tcItem, 0xcc, sizeof(tcItem));
851     tcItem.mask = TCIF_PARAM;
852     ret = SendMessage(hTab, TCM_GETITEM, -2, (LPARAM)&tcItem);
853     expect(FALSE, ret);
854     ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam);
855
856     flush_sequences(sequences, NUM_MSG_SEQUENCES);
857
858     tcItem.mask = TCIF_TEXT;
859     tcItem.pszText = &szText[0];
860     tcItem.cchTextMax = sizeof(szText);
861
862     strcpy(szText, "New Label");
863     ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n");
864     ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n");
865     expect_str("New Label", tcItem.pszText);
866
867     ok ( SendMessage(hTab, TCM_GETITEM, 1, (LPARAM) &tcItem), "Getting item failed.\n");
868     expect_str("Tab 2", tcItem.pszText);
869
870     ok_sequence(sequences, TAB_SEQ_INDEX, getset_item_seq, "Getset item test sequence", FALSE);
871     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset item test parent sequence", FALSE);
872
873     /* TCIS_BUTTONPRESSED doesn't depend on tab style */
874     memset(&tcItem, 0, sizeof(tcItem));
875     tcItem.mask = TCIF_STATE;
876     tcItem.dwStateMask = TCIS_BUTTONPRESSED;
877     tcItem.dwState = TCIS_BUTTONPRESSED;
878     ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n");
879     tcItem.dwState = 0;
880     ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n");
881     if (tcItem.dwState)
882     {
883         ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n");
884         /* next highlight item, test that dwStateMask actually masks */
885         tcItem.mask = TCIF_STATE;
886         tcItem.dwStateMask = TCIS_HIGHLIGHTED;
887         tcItem.dwState = TCIS_HIGHLIGHTED;
888         ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n");
889         tcItem.dwState = 0;
890         ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n");
891         ok (tcItem.dwState == TCIS_HIGHLIGHTED, "TCIS_HIGHLIGHTED should be set.\n");
892         tcItem.mask = TCIF_STATE;
893         tcItem.dwStateMask = TCIS_BUTTONPRESSED;
894         tcItem.dwState = 0;
895         ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n");
896         ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n");
897     }
898     else win_skip( "Item state mask not supported\n" );
899
900     DestroyWindow(hTab);
901 }
902
903 static void test_getset_tooltips(HWND parent_wnd, INT nTabs)
904 {
905     HWND hTab, toolTip;
906     char toolTipText[32] = "ToolTip Text Test";
907
908     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
909     ok(hTab != NULL, "Failed to create tab control\n");
910
911     flush_sequences(sequences, NUM_MSG_SEQUENCES);
912
913     toolTip = create_tooltip(hTab, toolTipText);
914     SendMessage(hTab, TCM_SETTOOLTIPS, (LPARAM) toolTip, 0);
915     ok (toolTip == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n");
916
917     SendMessage(hTab, TCM_SETTOOLTIPS, 0, 0);
918     ok (NULL  == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n");
919
920     ok_sequence(sequences, TAB_SEQ_INDEX, getset_tooltip_seq, "Getset tooltip test sequence", TRUE);
921     ok_sequence(sequences, PARENT_SEQ_INDEX, getset_tooltip_parent_seq, "Getset tooltip test parent sequence", TRUE);
922
923     DestroyWindow(hTab);
924 }
925
926 static void test_misc(HWND parent_wnd, INT nTabs)
927 {
928     HWND hTab;
929     RECT rTab;
930     INT nTabsRetrieved;
931     INT rowCount;
932     INT dpi;
933     HDC hdc;
934
935     ok(parent_wnd != NULL, "no parent window!\n");
936     flush_sequences(sequences, NUM_MSG_SEQUENCES);
937
938     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
939     ok(hTab != NULL, "Failed to create tab control\n");
940
941     if(!winetest_interactive)
942         ok_sequence(sequences, TAB_SEQ_INDEX, add_tab_to_parent,
943                     "Tab sequence, after adding tab control to parent", TRUE);
944     else
945         ok_sequence(sequences, TAB_SEQ_INDEX, add_tab_to_parent_interactive,
946                     "Tab sequence, after adding tab control to parent", TRUE);
947
948     if(!winetest_interactive)
949         ok_sequence(sequences, PARENT_SEQ_INDEX, add_tab_control_parent_seq,
950                     "Parent after sequence, adding tab control to parent", TRUE);
951     else
952         ok_sequence(sequences, PARENT_SEQ_INDEX, add_tab_control_parent_seq_interactive,
953                     "Parent after sequence, adding tab control to parent", TRUE);
954
955     flush_sequences(sequences, NUM_MSG_SEQUENCES);
956     ok(SendMessage(hTab, TCM_SETMINTABWIDTH, 0, -1) > 0,"TCM_SETMINTABWIDTH returned < 0\n");
957     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Set minTabWidth test parent sequence", FALSE);
958
959     /* Testing GetItemCount */
960     flush_sequences(sequences, NUM_MSG_SEQUENCES);
961     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
962     expect(nTabs, nTabsRetrieved);
963     ok_sequence(sequences, TAB_SEQ_INDEX, get_item_count_seq, "Get itemCount test sequence", FALSE);
964     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset itemCount test parent sequence", FALSE);
965
966     /* Testing GetRowCount */
967     flush_sequences(sequences, NUM_MSG_SEQUENCES);
968     rowCount = SendMessage(hTab, TCM_GETROWCOUNT, 0, 0);
969     expect(1, rowCount);
970     ok_sequence(sequences, TAB_SEQ_INDEX, get_row_count_seq, "Get rowCount test sequence", FALSE);
971     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Get rowCount test parent sequence", FALSE);
972
973     /* Testing GetItemRect */
974     flush_sequences(sequences, NUM_MSG_SEQUENCES);
975     ok(SendMessage(hTab, TCM_GETITEMRECT, 0, (LPARAM) &rTab), "GetItemRect failed.\n");
976
977     hdc = GetDC(hTab);
978     dpi = GetDeviceCaps(hdc, LOGPIXELSX);
979     ReleaseDC(hTab, hdc);
980     CheckSize(hTab, dpi, -1 , "Default Width");
981     ok_sequence(sequences, TAB_SEQ_INDEX, get_item_rect_seq, "Get itemRect test sequence", FALSE);
982     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Get itemRect test parent sequence", FALSE);
983
984     DestroyWindow(hTab);
985 }
986
987 static void test_adjustrect(HWND parent_wnd)
988 {
989     HWND hTab;
990     INT r;
991
992     ok(parent_wnd != NULL, "no parent window!\n");
993
994     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, 0, 0);
995     ok(hTab != NULL, "Failed to create tab control\n");
996
997     r = SendMessage(hTab, TCM_ADJUSTRECT, FALSE, 0);
998     expect(-1, r);
999
1000     r = SendMessage(hTab, TCM_ADJUSTRECT, TRUE, 0);
1001     expect(-1, r);
1002 }
1003
1004 static void test_insert_focus(HWND parent_wnd)
1005 {
1006     HWND hTab;
1007     INT nTabsRetrieved;
1008     INT r;
1009     TCITEM tcNewTab;
1010     DWORD mask = TCIF_TEXT|TCIF_IMAGE;
1011     static char tabName[] = "TAB";
1012     tcNewTab.mask = mask;
1013     tcNewTab.pszText = tabName;
1014
1015     ok(parent_wnd != NULL, "no parent window!\n");
1016
1017     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, mask, 0);
1018     ok(hTab != NULL, "Failed to create tab control\n");
1019
1020     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1021
1022     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1023     expect(0, nTabsRetrieved);
1024
1025     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1026     expect(-1, r);
1027
1028     tcNewTab.iImage = 1;
1029     r = SendMessage(hTab, TCM_INSERTITEM, 1, (LPARAM) &tcNewTab);
1030     expect(0, r);
1031
1032     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1033     expect(1, nTabsRetrieved);
1034
1035     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1036     expect(0, r);
1037
1038     tcNewTab.iImage = 2;
1039     r = SendMessage(hTab, TCM_INSERTITEM, 2, (LPARAM) &tcNewTab);
1040     expect(1, r);
1041
1042     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1043     expect(2, nTabsRetrieved);
1044
1045     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1046     expect(0, r);
1047
1048     r = SendMessage(hTab, TCM_SETCURFOCUS, -1, 0);
1049     expect(0, r);
1050
1051     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1052     expect(-1, r);
1053
1054     tcNewTab.iImage = 3;
1055     r = SendMessage(hTab, TCM_INSERTITEM, 3, (LPARAM) &tcNewTab);
1056     expect(2, r);
1057
1058     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1059     expect(2, r);
1060
1061     ok_sequence(sequences, TAB_SEQ_INDEX, insert_focus_seq, "insert_focus test sequence", FALSE);
1062     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "insert_focus parent test sequence", FALSE);
1063
1064     DestroyWindow(hTab);
1065 }
1066
1067 static void test_delete_focus(HWND parent_wnd)
1068 {
1069     HWND hTab;
1070     INT nTabsRetrieved;
1071     INT r;
1072
1073     ok(parent_wnd != NULL, "no parent window!\n");
1074
1075     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 2);
1076     ok(hTab != NULL, "Failed to create tab control\n");
1077
1078     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1079
1080     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1081     expect(2, nTabsRetrieved);
1082
1083     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1084     expect(0, r);
1085
1086     r = SendMessage(hTab, TCM_DELETEITEM, 1, 0);
1087     expect(1, r);
1088
1089     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1090     expect(1, nTabsRetrieved);
1091
1092     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1093     expect(0, r);
1094
1095     r = SendMessage(hTab, TCM_SETCURFOCUS, -1, 0);
1096     expect(0, r);
1097
1098     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1099     expect(-1, r);
1100
1101     r = SendMessage(hTab, TCM_DELETEITEM, 0, 0);
1102     expect(1, r);
1103
1104     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1105     expect(0, nTabsRetrieved);
1106
1107     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1108     expect(-1, r);
1109
1110     ok_sequence(sequences, TAB_SEQ_INDEX, delete_focus_seq, "delete_focus test sequence", FALSE);
1111     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "delete_focus parent test sequence", FALSE);
1112
1113     DestroyWindow(hTab);
1114 }
1115
1116 static void test_removeimage(HWND parent_wnd)
1117 {
1118     static const BYTE bits[32];
1119     HWND hwTab;
1120     INT i;
1121     TCITEM item;
1122     HICON hicon;
1123     HIMAGELIST himl = ImageList_Create(16, 16, ILC_COLOR, 3, 4);
1124
1125     hicon = CreateIcon(NULL, 16, 16, 1, 1, bits, bits);
1126     ImageList_AddIcon(himl, hicon);
1127     ImageList_AddIcon(himl, hicon);
1128     ImageList_AddIcon(himl, hicon);
1129
1130     hwTab = create_tabcontrol(TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE);
1131     SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
1132
1133     memset(&item, 0, sizeof(TCITEM));
1134     item.mask = TCIF_IMAGE;
1135
1136     for(i = 0; i < 3; i++) {
1137         SendMessage(hwTab, TCM_GETITEM, i, (LPARAM)&item);
1138         expect(i, item.iImage);
1139     }
1140
1141     /* remove image middle image */
1142     SendMessage(hwTab, TCM_REMOVEIMAGE, 1, 0);
1143     expect(2, ImageList_GetImageCount(himl));
1144     item.iImage = -1;
1145     SendMessage(hwTab, TCM_GETITEM, 0, (LPARAM)&item);
1146     expect(0, item.iImage);
1147     item.iImage = 0;
1148     SendMessage(hwTab, TCM_GETITEM, 1, (LPARAM)&item);
1149     expect(-1, item.iImage);
1150     item.iImage = 0;
1151     SendMessage(hwTab, TCM_GETITEM, 2, (LPARAM)&item);
1152     expect(1, item.iImage);
1153     /* remove first image */
1154     SendMessage(hwTab, TCM_REMOVEIMAGE, 0, 0);
1155     expect(1, ImageList_GetImageCount(himl));
1156     item.iImage = 0;
1157     SendMessage(hwTab, TCM_GETITEM, 0, (LPARAM)&item);
1158     expect(-1, item.iImage);
1159     item.iImage = 0;
1160     SendMessage(hwTab, TCM_GETITEM, 1, (LPARAM)&item);
1161     expect(-1, item.iImage);
1162     item.iImage = -1;
1163     SendMessage(hwTab, TCM_GETITEM, 2, (LPARAM)&item);
1164     expect(0, item.iImage);
1165     /* remove the last one */
1166     SendMessage(hwTab, TCM_REMOVEIMAGE, 0, 0);
1167     expect(0, ImageList_GetImageCount(himl));
1168     for(i = 0; i < 3; i++) {
1169         item.iImage = 0;
1170         SendMessage(hwTab, TCM_GETITEM, i, (LPARAM)&item);
1171         expect(-1, item.iImage);
1172     }
1173
1174     DestroyWindow(hwTab);
1175     ImageList_Destroy(himl);
1176     DestroyIcon(hicon);
1177 }
1178
1179 static void test_delete_selection(HWND parent_wnd)
1180 {
1181     HWND hTab;
1182     DWORD ret;
1183
1184     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 4);
1185     ok(hTab != NULL, "Failed to create tab control\n");
1186
1187     ret = SendMessage(hTab, TCM_SETCURSEL, 3, 0);
1188     expect(0, ret);
1189     ret = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
1190     expect(3, ret);
1191     /* delete selected item - selection goes to -1 */
1192     ret = SendMessage(hTab, TCM_DELETEITEM, 3, 0);
1193     expect(TRUE, ret);
1194
1195     ret = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
1196     expect(-1, ret);
1197
1198     DestroyWindow(hTab);
1199 }
1200
1201 START_TEST(tab)
1202 {
1203     HWND parent_wnd;
1204     LOGFONTA logfont;
1205
1206     lstrcpyA(logfont.lfFaceName, "Arial");
1207     memset(&logfont, 0, sizeof(logfont));
1208     logfont.lfHeight = -12;
1209     logfont.lfWeight = FW_NORMAL;
1210     logfont.lfCharSet = ANSI_CHARSET;
1211     hFont = CreateFontIndirectA(&logfont);
1212
1213     InitCommonControls();
1214
1215     trace ("Testing with default MinWidth\n");
1216     test_tab(-1);
1217     trace ("Testing with MinWidth set to -3\n");
1218     test_tab(-3);
1219     trace ("Testing with MinWidth set to 24\n");
1220     test_tab(24);
1221     trace ("Testing with MinWidth set to 54\n");
1222     test_tab(54);
1223     trace ("Testing with MinWidth set to 94\n");
1224     test_tab(94);
1225
1226     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1227
1228     parent_wnd = createParentWindow();
1229     ok(parent_wnd != NULL, "Failed to create parent window!\n");
1230
1231     test_curfocus(parent_wnd, 5);
1232     test_cursel(parent_wnd, 5);
1233     test_extendedstyle(parent_wnd, 5);
1234     test_unicodeformat(parent_wnd, 5);
1235     test_getset_item(parent_wnd, 5);
1236     test_getset_tooltips(parent_wnd, 5);
1237     test_misc(parent_wnd, 5);
1238
1239     test_adjustrect(parent_wnd);
1240
1241     test_insert_focus(parent_wnd);
1242     test_delete_focus(parent_wnd);
1243     test_delete_selection(parent_wnd);
1244     test_removeimage(parent_wnd);
1245
1246     DestroyWindow(parent_wnd);
1247 }