wine-wine/dlls/comctl32/tests/tab.c

1523 lines
50 KiB
C

/* Unit test suite for tab control.
*
* Copyright 2003 Vitaliy Margolen
* Copyright 2007 Hagop Hagopian
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include "wine/test.h"
#include "msg.h"
#define DEFAULT_MIN_TAB_WIDTH 54
#define TAB_PADDING_X 6
#define EXTRA_ICON_PADDING 3
#define MAX_TABLEN 32
#define NUM_MSG_SEQUENCES 2
#define PARENT_SEQ_INDEX 0
#define TAB_SEQ_INDEX 1
#define expect(expected, got) ok ( expected == got, "Expected %d, got %d\n", expected, got)
#define expect_str(expected, got)\
ok ( strcmp(expected, got) == 0, "Expected '%s', got '%s'\n", expected, got)
#define TabWidthPadded(padd_x, num) (DEFAULT_MIN_TAB_WIDTH - (TAB_PADDING_X - (padd_x)) * num)
static HIMAGELIST (WINAPI *pImageList_Create)(INT,INT,UINT,INT,INT);
static BOOL (WINAPI *pImageList_Destroy)(HIMAGELIST);
static INT (WINAPI *pImageList_GetImageCount)(HIMAGELIST);
static INT (WINAPI *pImageList_ReplaceIcon)(HIMAGELIST,INT,HICON);
static void CheckSize(HWND hwnd, INT width, INT height, const char *msg, int line)
{
RECT r;
SendMessageA(hwnd, TCM_GETITEMRECT, 0, (LPARAM)&r);
if (width >= 0 && height < 0)
ok_(__FILE__,line) (width == r.right - r.left, "%s: Expected width [%d] got [%d]\n",
msg, width, r.right - r.left);
else if (height >= 0 && width < 0)
ok_(__FILE__,line) (height == r.bottom - r.top, "%s: Expected height [%d] got [%d]\n",
msg, height, r.bottom - r.top);
else
ok_(__FILE__,line) ((width == r.right - r.left) && (height == r.bottom - r.top ),
"%s: Expected [%d,%d] got [%d,%d]\n", msg, width, height,
r.right - r.left, r.bottom - r.top);
}
#define CHECKSIZE(hwnd,width,height,msg) CheckSize(hwnd,width,height,msg,__LINE__)
static void TabCheckSetSize(HWND hwnd, INT set_width, INT set_height, INT exp_width,
INT exp_height, const char *msg, int line)
{
SendMessageA(hwnd, TCM_SETITEMSIZE, 0,
MAKELPARAM((set_width >= 0) ? set_width : 0, (set_height >= 0) ? set_height : 0));
if (winetest_interactive) RedrawWindow (hwnd, NULL, 0, RDW_UPDATENOW);
CheckSize(hwnd, exp_width, exp_height, msg, line);
}
#define TABCHECKSETSIZE(hwnd,set_width,set_height,exp_width,exp_height,msg) \
TabCheckSetSize(hwnd,set_width,set_height,exp_width,exp_height,msg,__LINE__)
static HFONT hFont;
static DRAWITEMSTRUCT g_drawitem;
static HWND parent_wnd;
static LRESULT tcn_selchanging_result;
static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
static const struct message empty_sequence[] = {
{ 0 }
};
static const struct message get_row_count_seq[] = {
{ TCM_GETROWCOUNT, sent|wparam|lparam, 0, 0 },
{ 0 }
};
static const struct message getset_cur_focus_seq[] = {
{ TCM_SETCURFOCUS, sent|lparam, 0 },
{ TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
{ TCM_SETCURFOCUS, sent|lparam, 0 },
{ TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
{ TCM_SETCURSEL, sent|lparam, 0 },
{ TCM_SETCURFOCUS, sent|lparam, 0 },
{ TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
{ 0 }
};
static const struct message getset_cur_sel_seq[] = {
{ TCM_SETCURSEL, sent|lparam, 0 },
{ TCM_GETCURSEL, sent|wparam|lparam, 0, 0 },
{ TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
{ TCM_SETCURSEL, sent|lparam, 0 },
{ TCM_GETCURSEL, sent|wparam|lparam, 0, 0 },
{ TCM_SETCURSEL, sent|lparam, 0 },
{ TCM_SETCURSEL, sent|lparam, 0 },
{ TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
{ 0 }
};
static const struct message getset_extended_style_seq[] = {
{ TCM_GETEXTENDEDSTYLE, sent|wparam|lparam, 0, 0 },
{ TCM_SETEXTENDEDSTYLE, sent },
{ TCM_GETEXTENDEDSTYLE, sent|wparam|lparam, 0, 0 },
{ TCM_SETEXTENDEDSTYLE, sent },
{ TCM_GETEXTENDEDSTYLE, sent|wparam|lparam, 0, 0 },
{ 0 }
};
static const struct message getset_unicode_format_seq[] = {
{ CCM_SETUNICODEFORMAT, sent|lparam, 0 },
{ CCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
{ CCM_SETUNICODEFORMAT, sent|lparam, 0 },
{ CCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
{ CCM_SETUNICODEFORMAT, sent|lparam, 0 },
{ 0 }
};
static const struct message getset_item_seq[] = {
{ TCM_SETITEMA, sent },
{ TCM_GETITEMA, sent },
{ TCM_GETITEMA, sent },
{ 0 }
};
static const struct message getset_tooltip_seq[] = {
{ WM_NOTIFYFORMAT, sent|optional },
{ WM_QUERYUISTATE, sent|wparam|lparam|optional, 0, 0 },
{ WM_WINDOWPOSCHANGING, sent|wparam, 0 },
{ WM_NOTIFYFORMAT, sent|optional },
{ TCM_SETTOOLTIPS, sent|lparam, 0 },
{ TCM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 },
{ TCM_SETTOOLTIPS, sent|lparam, 0 },
{ TCM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 },
{ 0 }
};
static const struct message getset_tooltip_parent_seq[] = {
{ WM_WINDOWPOSCHANGING, sent|wparam, 0 },
{ 0 }
};
static const struct message insert_focus_seq[] = {
{ TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
{ TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
{ TCM_INSERTITEMA, sent|wparam, 1 },
{ WM_NOTIFYFORMAT, sent|defwinproc|optional },
{ WM_QUERYUISTATE, sent|defwinproc|optional },
{ WM_PARENTNOTIFY, sent|defwinproc|optional },
{ TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
{ TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
{ TCM_INSERTITEMA, sent|wparam, 2 },
{ WM_NOTIFYFORMAT, sent|defwinproc|optional },
{ WM_QUERYUISTATE, sent|defwinproc|optional, },
{ WM_PARENTNOTIFY, sent|defwinproc|optional },
{ TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
{ TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
{ TCM_SETCURFOCUS, sent|wparam|lparam, -1, 0 },
{ TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
{ TCM_INSERTITEMA, sent|wparam, 3 },
{ TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
{ 0 }
};
static const struct message delete_focus_seq[] = {
{ TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
{ TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
{ TCM_DELETEITEM, sent|wparam|lparam, 1, 0 },
{ TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
{ TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
{ TCM_SETCURFOCUS, sent|wparam|lparam, -1, 0 },
{ TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
{ TCM_DELETEITEM, sent|wparam|lparam, 0, 0 },
{ TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
{ TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
{ 0 }
};
static const struct message rbuttonup_seq[] = {
{ WM_RBUTTONUP, sent|wparam|lparam, 0, 0 },
{ WM_CONTEXTMENU, sent|defwinproc },
{ 0 }
};
static const struct message full_selchange_parent_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, TCN_SELCHANGING },
{ WM_NOTIFY, sent|id, 0, 0, TCN_SELCHANGE },
{ 0 }
};
static const struct message selchanging_parent_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, TCN_SELCHANGING },
{ 0 }
};
static const struct message selchange_parent_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, TCN_SELCHANGE },
{ 0 }
};
static const struct message setfocus_parent_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, TCN_FOCUSCHANGE },
{ 0 }
};
static HWND
create_tabcontrol (DWORD style, DWORD mask)
{
HWND handle;
TCITEMA tcNewTab;
static char text1[] = "Tab 1",
text2[] = "Wide Tab 2",
text3[] = "T 3";
handle = CreateWindowA(WC_TABCONTROLA, "TestTab",
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | style, 10, 10, 300, 100, NULL,
NULL, NULL, 0);
ok(handle != NULL, "failed to create tab wnd\n");
SetWindowLongA(handle, GWL_STYLE, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | style);
SendMessageA(handle, WM_SETFONT, 0, (LPARAM)hFont);
tcNewTab.mask = mask;
tcNewTab.pszText = text1;
tcNewTab.iImage = 0;
SendMessageA(handle, TCM_INSERTITEMA, 0, (LPARAM)&tcNewTab);
tcNewTab.pszText = text2;
tcNewTab.iImage = 1;
SendMessageA(handle, TCM_INSERTITEMA, 1, (LPARAM)&tcNewTab);
tcNewTab.pszText = text3;
tcNewTab.iImage = 2;
SendMessageA(handle, TCM_INSERTITEMA, 2, (LPARAM)&tcNewTab);
if (winetest_interactive)
{
ShowWindow (handle, SW_SHOW);
RedrawWindow (handle, NULL, 0, RDW_UPDATENOW);
Sleep (1000);
}
return handle;
}
static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static LONG defwndproc_counter = 0;
struct message msg = { 0 };
LRESULT ret;
/* do not log painting messages */
if (message != WM_PAINT &&
message != WM_ERASEBKGND &&
message != WM_NCPAINT &&
message != WM_NCHITTEST &&
message != WM_GETTEXT &&
message != WM_GETICON &&
message != WM_DEVICECHANGE)
{
msg.message = message;
msg.flags = sent|wparam|lparam;
if (defwndproc_counter) msg.flags |= defwinproc;
msg.wParam = wParam;
msg.lParam = lParam;
if (message == WM_NOTIFY && lParam)
msg.id = ((NMHDR*)lParam)->code;
add_message(sequences, PARENT_SEQ_INDEX, &msg);
}
/* dump sent structure data */
if (message == WM_DRAWITEM)
g_drawitem = *(DRAWITEMSTRUCT*)lParam;
if (message == WM_NOTIFY)
{
NMHDR *nmhdr = (NMHDR *)lParam;
if (nmhdr && nmhdr->code == TCN_SELCHANGING)
return tcn_selchanging_result;
}
defwndproc_counter++;
ret = DefWindowProcA(hwnd, message, wParam, lParam);
defwndproc_counter--;
return ret;
}
static BOOL registerParentWindowClass(void)
{
WNDCLASSA cls;
cls.style = 0;
cls.lpfnWndProc = parent_wnd_proc;
cls.cbClsExtra = 0;
cls.cbWndExtra = 0;
cls.hInstance = GetModuleHandleA(NULL);
cls.hIcon = 0;
cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
cls.hbrBackground = GetStockObject(WHITE_BRUSH);
cls.lpszMenuName = NULL;
cls.lpszClassName = "Tab test parent class";
return RegisterClassA(&cls);
}
static HWND createParentWindow(void)
{
if (!registerParentWindowClass())
return NULL;
return CreateWindowExA(0, "Tab test parent class", "Tab test parent window",
WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE, 0, 0, 100, 100,
GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
}
static LRESULT WINAPI tab_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
static LONG defwndproc_counter = 0;
struct message msg = { 0 };
LRESULT ret;
/* do not log painting messages */
if (message != WM_PAINT &&
message != WM_ERASEBKGND &&
message != WM_NCPAINT &&
message != WM_NCHITTEST &&
message != WM_GETTEXT &&
message != WM_GETICON &&
message != WM_DEVICECHANGE)
{
msg.message = message;
msg.flags = sent|wparam|lparam;
if (defwndproc_counter) msg.flags |= defwinproc;
msg.wParam = wParam;
msg.lParam = lParam;
add_message(sequences, TAB_SEQ_INDEX, &msg);
}
defwndproc_counter++;
ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
defwndproc_counter--;
return ret;
}
static HWND createFilledTabControl(HWND parent_wnd, DWORD style, DWORD mask, INT nTabs)
{
HWND tabHandle;
TCITEMA tcNewTab;
WNDPROC oldproc;
RECT rect;
INT i;
GetClientRect(parent_wnd, &rect);
tabHandle = CreateWindowA(WC_TABCONTROLA, "TestTab",
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | style, 0, 0, rect.right,
rect.bottom, parent_wnd, NULL, NULL, 0);
ok(tabHandle != NULL, "failed to create tab wnd\n");
oldproc = (WNDPROC)SetWindowLongPtrA(tabHandle, GWLP_WNDPROC, (LONG_PTR)tab_subclass_proc);
SetWindowLongPtrA(tabHandle, GWLP_USERDATA, (LONG_PTR)oldproc);
tcNewTab.mask = mask;
for (i = 0; i < nTabs; i++)
{
char tabName[MAX_TABLEN];
sprintf(tabName, "Tab %d", i+1);
tcNewTab.pszText = tabName;
tcNewTab.iImage = i;
SendMessageA(tabHandle, TCM_INSERTITEMA, i, (LPARAM)&tcNewTab);
}
if (winetest_interactive)
{
ShowWindow (tabHandle, SW_SHOW);
RedrawWindow (tabHandle, NULL, 0, RDW_UPDATENOW);
Sleep (1000);
}
return tabHandle;
}
static HWND create_tooltip (HWND hTab, char toolTipText[])
{
HWND hwndTT;
TTTOOLINFOA ti;
LPSTR lptstr = toolTipText;
RECT rect;
/* Creating a tooltip window*/
hwndTT = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA, NULL,
WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, hTab, NULL, 0, NULL);
SetWindowPos(
hwndTT,
HWND_TOPMOST,
0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
GetClientRect (hTab, &rect);
/* Initialize members of toolinfo*/
ti.cbSize = sizeof(TTTOOLINFOA);
ti.uFlags = TTF_SUBCLASS;
ti.hwnd = hTab;
ti.hinst = 0;
ti.uId = 0;
ti.lpszText = lptstr;
ti.rect = rect;
/* Add toolinfo structure to the tooltip control */
SendMessageA(hwndTT, TTM_ADDTOOLA, 0, (LPARAM)&ti);
return hwndTT;
}
static void test_tab(INT nMinTabWidth)
{
HWND hwTab;
RECT rTab;
HIMAGELIST himl = pImageList_Create(21, 21, ILC_COLOR, 3, 4);
SIZE size;
HDC hdc;
HFONT hOldFont;
INT i, dpi, exp;
hwTab = create_tabcontrol(TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE);
SendMessageA(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
/* Get System default MinTabWidth */
if (nMinTabWidth < 0)
nMinTabWidth = SendMessageA(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
hdc = GetDC(hwTab);
dpi = GetDeviceCaps(hdc, LOGPIXELSX);
hOldFont = SelectObject(hdc, (HFONT)SendMessageA(hwTab, WM_GETFONT, 0, 0));
GetTextExtentPoint32A(hdc, "Tab 1", strlen("Tab 1"), &size);
trace("Tab1 text size: size.cx=%d size.cy=%d\n", size.cx, size.cy);
SelectObject(hdc, hOldFont);
ReleaseDC(hwTab, hdc);
trace (" TCS_FIXEDWIDTH tabs no icon...\n");
CHECKSIZE(hwTab, dpi, -1, "default width");
TABCHECKSETSIZE(hwTab, 50, 20, 50, 20, "set size");
TABCHECKSETSIZE(hwTab, 0, 1, 0, 1, "min size");
SendMessageA(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
trace (" TCS_FIXEDWIDTH tabs with icon...\n");
TABCHECKSETSIZE(hwTab, 50, 30, 50, 30, "set size > icon");
TABCHECKSETSIZE(hwTab, 20, 20, 25, 20, "set size < icon");
TABCHECKSETSIZE(hwTab, 0, 1, 25, 1, "min size");
DestroyWindow (hwTab);
hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BUTTONS, TCIF_TEXT|TCIF_IMAGE);
SendMessageA(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
hdc = GetDC(hwTab);
dpi = GetDeviceCaps(hdc, LOGPIXELSX);
ReleaseDC(hwTab, hdc);
trace (" TCS_FIXEDWIDTH buttons no icon...\n");
CHECKSIZE(hwTab, dpi, -1, "default width");
TABCHECKSETSIZE(hwTab, 20, 20, 20, 20, "set size 1");
TABCHECKSETSIZE(hwTab, 10, 50, 10, 50, "set size 2");
TABCHECKSETSIZE(hwTab, 0, 1, 0, 1, "min size");
SendMessageA(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
trace (" TCS_FIXEDWIDTH buttons with icon...\n");
TABCHECKSETSIZE(hwTab, 50, 30, 50, 30, "set size > icon");
TABCHECKSETSIZE(hwTab, 20, 20, 25, 20, "set size < icon");
TABCHECKSETSIZE(hwTab, 0, 1, 25, 1, "min size");
SendMessageA(hwTab, TCM_SETPADDING, 0, MAKELPARAM(4, 4));
TABCHECKSETSIZE(hwTab, 0, 1, 25, 1, "set padding, min size");
DestroyWindow (hwTab);
hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BOTTOM, TCIF_TEXT|TCIF_IMAGE);
SendMessageA(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
hdc = GetDC(hwTab);
dpi = GetDeviceCaps(hdc, LOGPIXELSX);
ReleaseDC(hwTab, hdc);
trace (" TCS_FIXEDWIDTH | TCS_BOTTOM tabs...\n");
CHECKSIZE(hwTab, dpi, -1, "no icon, default width");
TABCHECKSETSIZE(hwTab, 20, 20, 20, 20, "no icon, set size 1");
TABCHECKSETSIZE(hwTab, 10, 50, 10, 50, "no icon, set size 2");
TABCHECKSETSIZE(hwTab, 0, 1, 0, 1, "no icon, min size");
SendMessageA(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
TABCHECKSETSIZE(hwTab, 50, 30, 50, 30, "with icon, set size > icon");
TABCHECKSETSIZE(hwTab, 20, 20, 25, 20, "with icon, set size < icon");
TABCHECKSETSIZE(hwTab, 0, 1, 25, 1, "with icon, min size");
SendMessageA(hwTab, TCM_SETPADDING, 0, MAKELPARAM(4, 4));
TABCHECKSETSIZE(hwTab, 0, 1, 25, 1, "set padding, min size");
DestroyWindow (hwTab);
hwTab = create_tabcontrol(0, TCIF_TEXT|TCIF_IMAGE);
SendMessageA(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
trace (" non fixed width, with text...\n");
exp = max(size.cx +TAB_PADDING_X*2, (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth);
SendMessageA( hwTab, TCM_GETITEMRECT, 0, (LPARAM)&rTab );
ok( rTab.right - rTab.left == exp || broken(rTab.right - rTab.left == DEFAULT_MIN_TAB_WIDTH),
"no icon, default width: Expected width [%d] got [%d]\n", exp, rTab.right - rTab.left );
for (i=0; i<8; i++)
{
INT nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 2) : nMinTabWidth;
SendMessageA(hwTab, TCM_SETIMAGELIST, 0, 0);
SendMessageA(hwTab, TCM_SETPADDING, 0, MAKELPARAM(i, i));
TABCHECKSETSIZE(hwTab, 50, 20, max(size.cx + i*2, nTabWidth), 20, "no icon, set size");
TABCHECKSETSIZE(hwTab, 0, 1, max(size.cx + i*2, nTabWidth), 1, "no icon, min size");
SendMessageA(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 3) : nMinTabWidth;
TABCHECKSETSIZE(hwTab, 50, 30, max(size.cx + 21 + i*3, nTabWidth), 30, "with icon, set size > icon");
TABCHECKSETSIZE(hwTab, 20, 20, max(size.cx + 21 + i*3, nTabWidth), 20, "with icon, set size < icon");
TABCHECKSETSIZE(hwTab, 0, 1, max(size.cx + 21 + i*3, nTabWidth), 1, "with icon, min size");
}
DestroyWindow (hwTab);
hwTab = create_tabcontrol(0, TCIF_IMAGE);
SendMessageA(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
trace (" non fixed width, no text...\n");
exp = (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth;
SendMessageA( hwTab, TCM_GETITEMRECT, 0, (LPARAM)&rTab );
ok( rTab.right - rTab.left == exp || broken(rTab.right - rTab.left == DEFAULT_MIN_TAB_WIDTH),
"no icon, default width: Expected width [%d] got [%d]\n", exp, rTab.right - rTab.left );
for (i=0; i<8; i++)
{
INT nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 2) : nMinTabWidth;
SendMessageA(hwTab, TCM_SETIMAGELIST, 0, 0);
SendMessageA(hwTab, TCM_SETPADDING, 0, MAKELPARAM(i, i));
TABCHECKSETSIZE(hwTab, 50, 20, nTabWidth, 20, "no icon, set size");
TABCHECKSETSIZE(hwTab, 0, 1, nTabWidth, 1, "no icon, min size");
SendMessageA(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
if (i > 1 && nMinTabWidth > 0 && nMinTabWidth < DEFAULT_MIN_TAB_WIDTH)
nTabWidth += EXTRA_ICON_PADDING *(i-1);
TABCHECKSETSIZE(hwTab, 50, 30, nTabWidth, 30, "with icon, set size > icon");
TABCHECKSETSIZE(hwTab, 20, 20, nTabWidth, 20, "with icon, set size < icon");
TABCHECKSETSIZE(hwTab, 0, 1, nTabWidth, 1, "with icon, min size");
}
DestroyWindow (hwTab);
pImageList_Destroy(himl);
}
static void test_width(void)
{
trace ("Testing with default MinWidth\n");
test_tab(-1);
trace ("Testing with MinWidth set to -3\n");
test_tab(-3);
trace ("Testing with MinWidth set to 24\n");
test_tab(24);
trace ("Testing with MinWidth set to 54\n");
test_tab(54);
trace ("Testing with MinWidth set to 94\n");
test_tab(94);
}
static void test_curfocus(void)
{
const INT nTabs = 5;
INT ret;
HWND hTab;
hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
ok(hTab != NULL, "Failed to create tab control\n");
flush_sequences(sequences, NUM_MSG_SEQUENCES);
/* Testing CurFocus with largest appropriate value */
ret = SendMessageA(hTab, TCM_SETCURFOCUS, nTabs - 1, 0);
ok(ret == 0, "Unexpected ret value %d.\n", ret);
ret = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
ok(ret == nTabs - 1, "Unexpected focus index %d.\n", ret);
/* Testing CurFocus with negative value */
ret = SendMessageA(hTab, TCM_SETCURFOCUS, -10, 0);
ok(ret == 0, "Unexpected ret value %d.\n", ret);
ret = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
ok(ret == -1, "Unexpected focus index %d.\n", ret);
/* Testing CurFocus with value larger than number of tabs */
ret = SendMessageA(hTab, TCM_SETCURSEL, 1, 0);
ok(ret == -1, "Unexpected focus index %d.\n", ret);
ret = SendMessageA(hTab, TCM_SETCURFOCUS, nTabs + 1, 0);
ok(ret == 0, "Unexpected ret value %d.\n", ret);
ret = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
ok(ret == 1, "Unexpected focus index %d.\n", ret);
ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_focus_seq, "Set focused tab sequence", FALSE);
ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Set focused tab parent sequence", TRUE);
DestroyWindow(hTab);
/* TCS_BUTTONS */
hTab = createFilledTabControl(parent_wnd, TCS_BUTTONS, TCIF_TEXT|TCIF_IMAGE, nTabs);
ok(hTab != NULL, "Failed to create tab control\n");
flush_sequences(sequences, NUM_MSG_SEQUENCES);
/* Testing CurFocus with largest appropriate value */
ret = SendMessageA(hTab, TCM_SETCURFOCUS, nTabs - 1, 0);
ok(ret == 0, "Unexpected ret value %d.\n", ret);
ret = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
ok(ret == nTabs - 1, "Unexpected focus index %d.\n", ret);
/* Testing CurFocus with negative value */
ret = SendMessageA(hTab, TCM_SETCURFOCUS, -10, 0);
ok(ret == 0, "Unexpected ret value %d.\n", ret);
ret = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
todo_wine
ok(ret == nTabs - 1, "Unexpected focus index %d.\n", ret);
/* Testing CurFocus with value larger than number of tabs */
ret = SendMessageA(hTab, TCM_SETCURSEL, 1, 0);
todo_wine
ok(ret == 0, "Unexpected focus index %d.\n", ret);
ret = SendMessageA(hTab, TCM_SETCURFOCUS, nTabs + 1, 0);
ok(ret == 0, "Unexpected ret value %d.\n", ret);
ret = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
todo_wine
ok(ret == nTabs - 1, "Unexpected focus index %d.\n", ret);
ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_focus_seq, "TCS_BUTTONS: set focused tab sequence", FALSE);
ok_sequence(sequences, PARENT_SEQ_INDEX, setfocus_parent_seq, "TCS_BUTTONS: set focused tab parent sequence", TRUE);
DestroyWindow(hTab);
}
static void test_cursel(void)
{
const INT nTabs = 5;
INT selectionIndex;
INT focusIndex;
TCITEMA tcItem;
HWND hTab;
hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
ok(hTab != NULL, "Failed to create tab control\n");
flush_sequences(sequences, NUM_MSG_SEQUENCES);
/* Testing CurSel with largest appropriate value */
selectionIndex = SendMessageA(hTab, TCM_SETCURSEL, nTabs - 1, 0);
expect(0, selectionIndex);
selectionIndex = SendMessageA(hTab, TCM_GETCURSEL, 0, 0);
expect(nTabs-1, selectionIndex);
/* Focus should switch with selection */
focusIndex = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
expect(nTabs-1, focusIndex);
/* Testing CurSel with negative value */
SendMessageA(hTab, TCM_SETCURSEL, -10, 0);
selectionIndex = SendMessageA(hTab, TCM_GETCURSEL, 0, 0);
expect(-1, selectionIndex);
/* Testing CurSel with value larger than number of tabs */
selectionIndex = SendMessageA(hTab, TCM_SETCURSEL, 1, 0);
expect(-1, selectionIndex);
selectionIndex = SendMessageA(hTab, TCM_SETCURSEL, nTabs + 1, 0);
expect(-1, selectionIndex);
selectionIndex = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
expect(1, selectionIndex);
ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_sel_seq, "Getset curSel test sequence", FALSE);
ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset curSel test parent sequence", FALSE);
/* selected item should have TCIS_BUTTONPRESSED state
It doesn't depend on button state */
memset(&tcItem, 0, sizeof(TCITEMA));
tcItem.mask = TCIF_STATE;
tcItem.dwStateMask = TCIS_BUTTONPRESSED;
selectionIndex = SendMessageA(hTab, TCM_GETCURSEL, 0, 0);
SendMessageA(hTab, TCM_GETITEMA, selectionIndex, (LPARAM)&tcItem);
ok (tcItem.dwState & TCIS_BUTTONPRESSED || broken(tcItem.dwState == 0), /* older comctl32 */
"Selected item should have TCIS_BUTTONPRESSED\n");
/* now deselect all and check previously selected item state */
focusIndex = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
ok(focusIndex == 1, "got %d\n", focusIndex);
selectionIndex = SendMessageA(hTab, TCM_SETCURSEL, -1, 0);
ok(selectionIndex == 1, "got %d\n", selectionIndex);
memset(&tcItem, 0, sizeof(TCITEMA));
/* focus is reset too */
focusIndex = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
ok(focusIndex == -1, "got %d\n", focusIndex);
tcItem.mask = TCIF_STATE;
tcItem.dwStateMask = TCIS_BUTTONPRESSED;
SendMessageA(hTab, TCM_GETITEMA, selectionIndex, (LPARAM)&tcItem);
ok(tcItem.dwState == 0, "got state %d\n", tcItem.dwState);
DestroyWindow(hTab);
}
static void test_extendedstyle(void)
{
const INT nTabs = 5;
DWORD prevExtendedStyle;
DWORD extendedStyle;
HWND hTab;
hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
ok(hTab != NULL, "Failed to create tab control\n");
flush_sequences(sequences, NUM_MSG_SEQUENCES);
/* Testing Flat Separators */
extendedStyle = SendMessageA(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
prevExtendedStyle = SendMessageA(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_FLATSEPARATORS);
expect(extendedStyle, prevExtendedStyle);
extendedStyle = SendMessageA(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
expect(TCS_EX_FLATSEPARATORS, extendedStyle);
/* Testing Register Drop */
prevExtendedStyle = SendMessageA(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_REGISTERDROP);
expect(extendedStyle, prevExtendedStyle);
extendedStyle = SendMessageA(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
todo_wine{
expect(TCS_EX_REGISTERDROP, extendedStyle);
}
ok_sequence(sequences, TAB_SEQ_INDEX, getset_extended_style_seq, "Getset extendedStyle test sequence", FALSE);
ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset extendedStyle test parent sequence", FALSE);
DestroyWindow(hTab);
}
static void test_unicodeformat(void)
{
const INT nTabs = 5;
INT unicodeFormat;
HWND hTab;
hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
ok(hTab != NULL, "Failed to create tab control\n");
flush_sequences(sequences, NUM_MSG_SEQUENCES);
unicodeFormat = SendMessageA(hTab, TCM_SETUNICODEFORMAT, TRUE, 0);
todo_wine{
expect(0, unicodeFormat);
}
unicodeFormat = SendMessageA(hTab, TCM_GETUNICODEFORMAT, 0, 0);
expect(1, unicodeFormat);
unicodeFormat = SendMessageA(hTab, TCM_SETUNICODEFORMAT, FALSE, 0);
expect(1, unicodeFormat);
unicodeFormat = SendMessageA(hTab, TCM_GETUNICODEFORMAT, 0, 0);
expect(0, unicodeFormat);
unicodeFormat = SendMessageA(hTab, TCM_SETUNICODEFORMAT, TRUE, 0);
expect(0, unicodeFormat);
ok_sequence(sequences, TAB_SEQ_INDEX, getset_unicode_format_seq, "Getset unicodeFormat test sequence", FALSE);
ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset unicodeFormat test parent sequence", FALSE);
DestroyWindow(hTab);
}
static void test_getset_item(void)
{
char szText[32] = "New Label";
const INT nTabs = 5;
TCITEMA tcItem;
LPARAM lparam;
DWORD ret;
HWND hTab;
hTab = CreateWindowA(
WC_TABCONTROLA,
"TestTab",
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | TCS_FIXEDWIDTH | TCS_OWNERDRAWFIXED,
10, 10, 300, 100,
parent_wnd, NULL, NULL, 0);
ok(GetParent(hTab) == NULL, "got %p, expected null parent\n", GetParent(hTab));
ret = SendMessageA(hTab, TCM_SETITEMEXTRA, sizeof(LPARAM)-1, 0);
ok(ret == TRUE, "got %d\n", ret);
/* set some item data */
tcItem.lParam = ~0;
tcItem.mask = TCIF_PARAM;
ret = SendMessageA(hTab, TCM_INSERTITEMA, 0, (LPARAM)&tcItem);
ok(ret == 0, "got %d\n", ret);
/* all sizeof(LPARAM) returned anyway when using sizeof(LPARAM)-1 size */
memset(&lparam, 0xaa, sizeof(lparam));
tcItem.lParam = lparam;
tcItem.mask = TCIF_PARAM;
ret = SendMessageA(hTab, TCM_GETITEMA, 0, (LPARAM)&tcItem);
expect(TRUE, ret);
/* everything higher specified size is preserved */
memset(&lparam, 0xff, sizeof(lparam)-1);
ok(tcItem.lParam == lparam, "Expected 0x%lx, got 0x%lx\n", lparam, tcItem.lParam);
DestroyWindow(hTab);
hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
ok(hTab != NULL, "Failed to create tab control\n");
/* passing invalid index should result in initialization to zero
for members mentioned in mask requested */
/* valid range here is [0,4] */
memset(&tcItem, 0xcc, sizeof(tcItem));
tcItem.mask = TCIF_PARAM;
ret = SendMessageA(hTab, TCM_GETITEMA, 5, (LPARAM)&tcItem);
expect(FALSE, ret);
ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam);
memset(&tcItem, 0xcc, sizeof(tcItem));
tcItem.mask = TCIF_IMAGE;
ret = SendMessageA(hTab, TCM_GETITEMA, 5, (LPARAM)&tcItem);
expect(FALSE, ret);
expect(0, tcItem.iImage);
memset(&tcItem, 0xcc, sizeof(tcItem));
tcItem.mask = TCIF_TEXT;
tcItem.pszText = szText;
szText[0] = 'a';
ret = SendMessageA(hTab, TCM_GETITEMA, 5, (LPARAM)&tcItem);
expect(FALSE, ret);
expect('a', szText[0]);
memset(&tcItem, 0xcc, sizeof(tcItem));
tcItem.mask = TCIF_STATE;
tcItem.dwStateMask = 0;
tcItem.dwState = TCIS_BUTTONPRESSED;
ret = SendMessageA(hTab, TCM_GETITEMA, 5, (LPARAM)&tcItem);
expect(FALSE, ret);
ok(tcItem.dwState == 0, "Expected zero dwState, got %u\n", tcItem.dwState);
memset(&tcItem, 0xcc, sizeof(tcItem));
tcItem.mask = TCIF_STATE;
tcItem.dwStateMask = TCIS_BUTTONPRESSED;
tcItem.dwState = TCIS_BUTTONPRESSED;
ret = SendMessageA(hTab, TCM_GETITEMA, 5, (LPARAM)&tcItem);
expect(FALSE, ret);
ok(tcItem.dwState == 0, "Expected zero dwState\n");
/* check with negative index to be sure */
memset(&tcItem, 0xcc, sizeof(tcItem));
tcItem.mask = TCIF_PARAM;
ret = SendMessageA(hTab, TCM_GETITEMA, -1, (LPARAM)&tcItem);
expect(FALSE, ret);
ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam);
memset(&tcItem, 0xcc, sizeof(tcItem));
tcItem.mask = TCIF_PARAM;
ret = SendMessageA(hTab, TCM_GETITEMA, -2, (LPARAM)&tcItem);
expect(FALSE, ret);
ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
tcItem.mask = TCIF_TEXT;
tcItem.pszText = &szText[0];
tcItem.cchTextMax = sizeof(szText);
strcpy(szText, "New Label");
ok(SendMessageA(hTab, TCM_SETITEMA, 0, (LPARAM)&tcItem), "Setting new item failed.\n");
ok(SendMessageA(hTab, TCM_GETITEMA, 0, (LPARAM)&tcItem), "Getting item failed.\n");
expect_str("New Label", tcItem.pszText);
ok(SendMessageA(hTab, TCM_GETITEMA, 1, (LPARAM)&tcItem), "Getting item failed.\n");
expect_str("Tab 2", tcItem.pszText);
ok_sequence(sequences, TAB_SEQ_INDEX, getset_item_seq, "Getset item test sequence", FALSE);
ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset item test parent sequence", FALSE);
/* TCIS_BUTTONPRESSED doesn't depend on tab style */
memset(&tcItem, 0, sizeof(tcItem));
tcItem.mask = TCIF_STATE;
tcItem.dwStateMask = TCIS_BUTTONPRESSED;
tcItem.dwState = TCIS_BUTTONPRESSED;
ok(SendMessageA(hTab, TCM_SETITEMA, 0, (LPARAM)&tcItem), "Setting new item failed.\n");
tcItem.dwState = 0;
ok(SendMessageA(hTab, TCM_GETITEMA, 0, (LPARAM)&tcItem), "Getting item failed.\n");
if (tcItem.dwState)
{
ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n");
/* next highlight item, test that dwStateMask actually masks */
tcItem.mask = TCIF_STATE;
tcItem.dwStateMask = TCIS_HIGHLIGHTED;
tcItem.dwState = TCIS_HIGHLIGHTED;
ok(SendMessageA(hTab, TCM_SETITEMA, 0, (LPARAM)&tcItem), "Setting new item failed.\n");
tcItem.dwState = 0;
ok(SendMessageA(hTab, TCM_GETITEMA, 0, (LPARAM)&tcItem), "Getting item failed.\n");
ok (tcItem.dwState == TCIS_HIGHLIGHTED, "TCIS_HIGHLIGHTED should be set.\n");
tcItem.mask = TCIF_STATE;
tcItem.dwStateMask = TCIS_BUTTONPRESSED;
tcItem.dwState = 0;
ok(SendMessageA(hTab, TCM_GETITEMA, 0, (LPARAM)&tcItem), "Getting item failed.\n");
ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n");
}
else win_skip( "Item state mask not supported\n" );
DestroyWindow(hTab);
}
static void test_getset_tooltips(void)
{
char toolTipText[32] = "ToolTip Text Test";
HWND hTab, toolTip, hwnd;
const INT nTabs = 5;
int ret;
hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
ok(hTab != NULL, "Failed to create tab control\n");
flush_sequences(sequences, NUM_MSG_SEQUENCES);
toolTip = create_tooltip(hTab, toolTipText);
ret = SendMessageA(hTab, TCM_SETTOOLTIPS, (WPARAM)toolTip, 0);
ok(ret == 0, "Unexpected ret value %d.\n", ret);
hwnd = (HWND)SendMessageA(hTab, TCM_GETTOOLTIPS, 0, 0);
ok(toolTip == hwnd, "Unexpected tooltip window.\n");
ret = SendMessageA(hTab, TCM_SETTOOLTIPS, 0, 0);
ok(ret == 0, "Unexpected ret value %d.\n", ret);
hwnd = (HWND)SendMessageA(hTab, TCM_GETTOOLTIPS, 0, 0);
ok(hwnd == NULL, "Unexpected tooltip window.\n");
ok(IsWindow(toolTip), "Expected tooltip window to be alive.\n");
ok_sequence(sequences, TAB_SEQ_INDEX, getset_tooltip_seq, "Getset tooltip test sequence", TRUE);
ok_sequence(sequences, PARENT_SEQ_INDEX, getset_tooltip_parent_seq, "Getset tooltip test parent sequence", TRUE);
DestroyWindow(hTab);
DestroyWindow(toolTip);
}
static void test_adjustrect(void)
{
HWND hTab;
INT r;
ok(parent_wnd != NULL, "no parent window!\n");
hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, 0, 0);
ok(hTab != NULL, "Failed to create tab control\n");
r = SendMessageA(hTab, TCM_ADJUSTRECT, FALSE, 0);
expect(-1, r);
r = SendMessageA(hTab, TCM_ADJUSTRECT, TRUE, 0);
expect(-1, r);
}
static void test_insert_focus(void)
{
HWND hTab;
INT nTabsRetrieved;
INT r;
TCITEMA tcNewTab;
DWORD mask = TCIF_TEXT|TCIF_IMAGE;
static char tabName[] = "TAB";
tcNewTab.mask = mask;
tcNewTab.pszText = tabName;
ok(parent_wnd != NULL, "no parent window!\n");
hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, mask, 0);
ok(hTab != NULL, "Failed to create tab control\n");
r = SendMessageA(hTab, TCM_GETCURSEL, 0, 0);
expect(-1, r);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
nTabsRetrieved = SendMessageA(hTab, TCM_GETITEMCOUNT, 0, 0);
expect(0, nTabsRetrieved);
r = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
expect(-1, r);
tcNewTab.iImage = 1;
r = SendMessageA(hTab, TCM_INSERTITEMA, 1, (LPARAM)&tcNewTab);
expect(0, r);
nTabsRetrieved = SendMessageA(hTab, TCM_GETITEMCOUNT, 0, 0);
expect(1, nTabsRetrieved);
r = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
expect(0, r);
tcNewTab.iImage = 2;
r = SendMessageA(hTab, TCM_INSERTITEMA, 2, (LPARAM)&tcNewTab);
expect(1, r);
nTabsRetrieved = SendMessageA(hTab, TCM_GETITEMCOUNT, 0, 0);
expect(2, nTabsRetrieved);
r = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
expect(0, r);
r = SendMessageA(hTab, TCM_SETCURFOCUS, -1, 0);
expect(0, r);
r = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
expect(-1, r);
tcNewTab.iImage = 3;
r = SendMessageA(hTab, TCM_INSERTITEMA, 3, (LPARAM)&tcNewTab);
expect(2, r);
r = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
expect(2, r);
ok_sequence(sequences, TAB_SEQ_INDEX, insert_focus_seq, "insert_focus test sequence", FALSE);
ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "insert_focus parent test sequence", TRUE);
DestroyWindow(hTab);
}
static void test_delete_focus(void)
{
HWND hTab;
INT nTabsRetrieved;
INT r;
ok(parent_wnd != NULL, "no parent window!\n");
hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 2);
ok(hTab != NULL, "Failed to create tab control\n");
flush_sequences(sequences, NUM_MSG_SEQUENCES);
nTabsRetrieved = SendMessageA(hTab, TCM_GETITEMCOUNT, 0, 0);
expect(2, nTabsRetrieved);
r = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
expect(0, r);
r = SendMessageA(hTab, TCM_DELETEITEM, 1, 0);
expect(1, r);
nTabsRetrieved = SendMessageA(hTab, TCM_GETITEMCOUNT, 0, 0);
expect(1, nTabsRetrieved);
r = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
expect(0, r);
r = SendMessageA(hTab, TCM_SETCURFOCUS, -1, 0);
expect(0, r);
r = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
expect(-1, r);
r = SendMessageA(hTab, TCM_DELETEITEM, 0, 0);
expect(1, r);
nTabsRetrieved = SendMessageA(hTab, TCM_GETITEMCOUNT, 0, 0);
expect(0, nTabsRetrieved);
r = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
expect(-1, r);
ok_sequence(sequences, TAB_SEQ_INDEX, delete_focus_seq, "delete_focus test sequence", FALSE);
ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "delete_focus parent test sequence", TRUE);
DestroyWindow(hTab);
}
static void test_removeimage(void)
{
static const BYTE bits[32];
HWND hwTab;
INT i;
TCITEMA item;
HICON hicon;
HIMAGELIST himl = pImageList_Create(16, 16, ILC_COLOR, 3, 4);
hicon = CreateIcon(NULL, 16, 16, 1, 1, bits, bits);
pImageList_ReplaceIcon(himl, -1, hicon);
pImageList_ReplaceIcon(himl, -1, hicon);
pImageList_ReplaceIcon(himl, -1, hicon);
hwTab = create_tabcontrol(TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE);
SendMessageA(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
memset(&item, 0, sizeof(TCITEMA));
item.mask = TCIF_IMAGE;
for(i = 0; i < 3; i++) {
SendMessageA(hwTab, TCM_GETITEMA, i, (LPARAM)&item);
expect(i, item.iImage);
}
/* remove image middle image */
SendMessageA(hwTab, TCM_REMOVEIMAGE, 1, 0);
i = pImageList_GetImageCount(himl);
ok(i == 2, "Unexpected image count %d.\n", i);
item.iImage = -1;
SendMessageA(hwTab, TCM_GETITEMA, 0, (LPARAM)&item);
expect(0, item.iImage);
item.iImage = 0;
SendMessageA(hwTab, TCM_GETITEMA, 1, (LPARAM)&item);
expect(-1, item.iImage);
item.iImage = 0;
SendMessageA(hwTab, TCM_GETITEMA, 2, (LPARAM)&item);
expect(1, item.iImage);
/* remove first image */
SendMessageA(hwTab, TCM_REMOVEIMAGE, 0, 0);
i = pImageList_GetImageCount(himl);
ok(i == 1, "Unexpected image count %d.\n", i);
item.iImage = 0;
SendMessageA(hwTab, TCM_GETITEMA, 0, (LPARAM)&item);
expect(-1, item.iImage);
item.iImage = 0;
SendMessageA(hwTab, TCM_GETITEMA, 1, (LPARAM)&item);
expect(-1, item.iImage);
item.iImage = -1;
SendMessageA(hwTab, TCM_GETITEMA, 2, (LPARAM)&item);
expect(0, item.iImage);
/* remove the last one */
SendMessageA(hwTab, TCM_REMOVEIMAGE, 0, 0);
i = pImageList_GetImageCount(himl);
ok(i == 0, "Unexpected image count %d.\n", i);
for(i = 0; i < 3; i++) {
item.iImage = 0;
SendMessageA(hwTab, TCM_GETITEMA, i, (LPARAM)&item);
expect(-1, item.iImage);
}
DestroyWindow(hwTab);
pImageList_Destroy(himl);
DestroyIcon(hicon);
}
static void test_delete_selection(void)
{
HWND hTab;
INT ret;
hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 4);
ok(hTab != NULL, "Failed to create tab control\n");
ret = SendMessageA(hTab, TCM_SETCURSEL, 3, 0);
expect(0, ret);
ret = SendMessageA(hTab, TCM_GETCURSEL, 0, 0);
expect(3, ret);
/* delete selected item - selection goes to -1 */
ret = SendMessageA(hTab, TCM_DELETEITEM, 3, 0);
expect(TRUE, ret);
ret = SendMessageA(hTab, TCM_GETCURSEL, 0, 0);
expect(-1, ret);
DestroyWindow(hTab);
}
static void test_TCM_SETITEMEXTRA(void)
{
HWND hTab;
DWORD ret;
hTab = CreateWindowA(
WC_TABCONTROLA,
"TestTab",
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | TCS_FIXEDWIDTH,
10, 10, 300, 100,
parent_wnd, NULL, NULL, 0);
/* zero is valid size too */
ret = SendMessageA(hTab, TCM_SETITEMEXTRA, 0, 0);
if (ret == FALSE)
{
win_skip("TCM_SETITEMEXTRA not supported\n");
DestroyWindow(hTab);
return;
}
ret = SendMessageA(hTab, TCM_SETITEMEXTRA, -1, 0);
ok(ret == FALSE, "got %d\n", ret);
ret = SendMessageA(hTab, TCM_SETITEMEXTRA, 2, 0);
ok(ret == TRUE, "got %d\n", ret);
DestroyWindow(hTab);
/* it's not possible to change extra data size for control with tabs */
hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 4);
ok(hTab != NULL, "Failed to create tab control\n");
ret = SendMessageA(hTab, TCM_SETITEMEXTRA, 2, 0);
ok(ret == FALSE, "got %d\n", ret);
DestroyWindow(hTab);
}
static void test_TCS_OWNERDRAWFIXED(void)
{
LPARAM lparam;
ULONG_PTR itemdata, itemdata2;
TCITEMA item;
HWND hTab;
BOOL ret;
hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH|TCS_OWNERDRAWFIXED, TCIF_TEXT|TCIF_IMAGE, 4);
ok(hTab != NULL, "Failed to create tab control\n");
ok(GetParent(hTab) == NULL, "got %p, expected null parent\n", GetParent(hTab));
/* set some item data */
memset(&lparam, 0xde, sizeof(LPARAM));
item.mask = TCIF_PARAM;
item.lParam = lparam;
ret = SendMessageA(hTab, TCM_SETITEMA, 0, (LPARAM)&item);
ok(ret == TRUE, "got %d\n", ret);
memset(&g_drawitem, 0, sizeof(g_drawitem));
ShowWindow(hTab, SW_SHOW);
RedrawWindow(hTab, NULL, 0, RDW_UPDATENOW);
itemdata = 0;
memset(&itemdata, 0xde, 4);
ok(g_drawitem.itemData == itemdata, "got 0x%lx, expected 0x%lx\n", g_drawitem.itemData, itemdata);
DestroyWindow(hTab);
/* now with custom extra data length */
hTab = CreateWindowA(
WC_TABCONTROLA,
"TestTab",
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | TCS_FIXEDWIDTH | TCS_OWNERDRAWFIXED,
10, 10, 300, 100,
parent_wnd, NULL, NULL, 0);
ok(GetParent(hTab) == NULL, "got %p, expected null parent\n", GetParent(hTab));
ret = SendMessageA(hTab, TCM_SETITEMEXTRA, sizeof(LPARAM)+1, 0);
ok(ret == TRUE, "got %d\n", ret);
/* set some item data */
memset(&lparam, 0xde, sizeof(LPARAM));
item.mask = TCIF_PARAM;
item.lParam = lparam;
ret = SendMessageA(hTab, TCM_INSERTITEMA, 0, (LPARAM)&item);
ok(ret == 0, "got %d\n", ret);
memset(&g_drawitem, 0, sizeof(g_drawitem));
ShowWindow(hTab, SW_SHOW);
RedrawWindow(hTab, NULL, 0, RDW_UPDATENOW);
memset(&itemdata, 0xde, sizeof(ULONG_PTR));
ok(*(ULONG_PTR*)g_drawitem.itemData == itemdata, "got 0x%lx, expected 0x%lx\n", g_drawitem.itemData, itemdata);
DestroyWindow(hTab);
/* same thing, but size smaller than default */
hTab = CreateWindowA(
WC_TABCONTROLA,
"TestTab",
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | TCS_FIXEDWIDTH | TCS_OWNERDRAWFIXED,
10, 10, 300, 100,
parent_wnd, NULL, NULL, 0);
ok(GetParent(hTab) == NULL, "got %p, expected null parent\n", GetParent(hTab));
ret = SendMessageA(hTab, TCM_SETITEMEXTRA, sizeof(LPARAM)-1, 0);
ok(ret == TRUE, "got %d\n", ret);
memset(&lparam, 0xde, sizeof(lparam));
item.mask = TCIF_PARAM;
item.lParam = lparam;
ret = SendMessageA(hTab, TCM_INSERTITEMA, 0, (LPARAM)&item);
ok(ret == 0, "got %d\n", ret);
memset(&g_drawitem, 0, sizeof(g_drawitem));
ShowWindow(hTab, SW_SHOW);
RedrawWindow(hTab, NULL, 0, RDW_UPDATENOW);
itemdata = itemdata2 = 0;
memset(&itemdata, 0xde, 4);
memset(&itemdata2, 0xde, sizeof(LPARAM)-1);
ok(g_drawitem.itemData == itemdata || broken(g_drawitem.itemData == itemdata2) /* win98 */,
"got 0x%lx, expected 0x%lx\n", g_drawitem.itemData, itemdata);
DestroyWindow(hTab);
}
static void test_WM_CONTEXTMENU(void)
{
HWND hTab;
hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 4);
ok(hTab != NULL, "Failed to create tab control\n");
flush_sequences(sequences, NUM_MSG_SEQUENCES);
SendMessageA(hTab, WM_RBUTTONUP, 0, 0);
ok_sequence(sequences, TAB_SEQ_INDEX, rbuttonup_seq, "WM_RBUTTONUP response sequence", FALSE);
DestroyWindow(hTab);
}
struct tabcreate_style {
DWORD style;
DWORD act_style;
};
static const struct tabcreate_style create_styles[] =
{
{ WS_CHILD|TCS_BOTTOM|TCS_VERTICAL, WS_CHILD|WS_CLIPSIBLINGS|TCS_BOTTOM|TCS_VERTICAL|TCS_MULTILINE },
{ WS_CHILD|TCS_VERTICAL, WS_CHILD|WS_CLIPSIBLINGS|TCS_VERTICAL|TCS_MULTILINE },
{ 0 }
};
static void test_create(void)
{
const struct tabcreate_style *ptr = create_styles;
DWORD style;
HWND hTab;
while (ptr->style)
{
hTab = CreateWindowA(WC_TABCONTROLA, "TestTab", ptr->style,
10, 10, 300, 100, parent_wnd, NULL, NULL, 0);
style = GetWindowLongA(hTab, GWL_STYLE);
ok(style == ptr->act_style, "expected style 0x%08x, got style 0x%08x\n", ptr->act_style, style);
DestroyWindow(hTab);
ptr++;
}
}
static void init_functions(void)
{
HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
#define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f);
X(ImageList_Create);
X(ImageList_Destroy);
X(ImageList_GetImageCount);
X(ImageList_ReplaceIcon);
#undef X
}
static void test_TCN_SELCHANGING(void)
{
const INT nTabs = 5;
HWND hTab;
INT ret;
hTab = createFilledTabControl(parent_wnd, WS_CHILD|TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
ok(hTab != NULL, "Failed to create tab control\n");
/* Initially first tab is focused. */
ret = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
ok(ret == 0, "Unexpected tab focus %d.\n", ret);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
/* Setting focus to currently focused item should do nothing. */
ret = SendMessageA(hTab, TCM_SETCURFOCUS, 0, 0);
ok(ret == 0, "Unexpected ret value %d.\n", ret);
ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Set focus to focused tab sequence", FALSE);
/* Allow selection change. */
flush_sequences(sequences, NUM_MSG_SEQUENCES);
tcn_selchanging_result = 0;
ret = SendMessageA(hTab, TCM_SETCURFOCUS, nTabs - 1, 0);
ok(ret == 0, "Unexpected ret value %d.\n", ret);
ok_sequence(sequences, PARENT_SEQ_INDEX, full_selchange_parent_seq, "Focus change allowed sequence", FALSE);
ret = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
ok(ret == nTabs - 1, "Unexpected focused tab %d.\n", ret);
ret = SendMessageA(hTab, TCM_GETCURSEL, 0, 0);
ok(ret == nTabs - 1, "Unexpected selected tab %d.\n", ret);
/* Forbid selection change. */
flush_sequences(sequences, NUM_MSG_SEQUENCES);
tcn_selchanging_result = 1;
ret = SendMessageA(hTab, TCM_SETCURFOCUS, 0, 0);
ok(ret == 0, "Unexpected ret value %d.\n", ret);
ok_sequence(sequences, PARENT_SEQ_INDEX, selchanging_parent_seq, "Focus change disallowed sequence", FALSE);
ret = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
todo_wine
ok(ret == nTabs - 1, "Unexpected focused tab %d.\n", ret);
ret = SendMessageA(hTab, TCM_GETCURSEL, 0, 0);
todo_wine
ok(ret == nTabs - 1, "Unexpected selected tab %d.\n", ret);
/* Removing focus sends only TCN_SELCHANGE */
flush_sequences(sequences, NUM_MSG_SEQUENCES);
ret = SendMessageA(hTab, TCM_SETCURFOCUS, -1, 0);
ok(ret == 0, "Unexpected ret value %d.\n", ret);
ok_sequence(sequences, PARENT_SEQ_INDEX, selchange_parent_seq, "Remove focus sequence", FALSE);
ret = SendMessageA(hTab, TCM_GETCURFOCUS, 0, 0);
ok(ret == -1, "Unexpected focused tab %d.\n", ret);
tcn_selchanging_result = 0;
DestroyWindow(hTab);
}
static void test_TCM_GETROWCOUNT(void)
{
const INT nTabs = 5;
HWND hTab;
INT count;
flush_sequences(sequences, NUM_MSG_SEQUENCES);
hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
ok(hTab != NULL, "Failed to create tab control\n");
flush_sequences(sequences, NUM_MSG_SEQUENCES);
count = SendMessageA(hTab, TCM_GETROWCOUNT, 0, 0);
ok(count == 1, "Unexpected row count %d.\n", count);
ok_sequence(sequences, TAB_SEQ_INDEX, get_row_count_seq, "Get rowCount test sequence", FALSE);
ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Get rowCount test parent sequence", FALSE);
DestroyWindow(hTab);
}
START_TEST(tab)
{
LOGFONTA logfont;
lstrcpyA(logfont.lfFaceName, "Arial");
memset(&logfont, 0, sizeof(logfont));
logfont.lfHeight = -12;
logfont.lfWeight = FW_NORMAL;
logfont.lfCharSet = ANSI_CHARSET;
hFont = CreateFontIndirectA(&logfont);
init_functions();
init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
parent_wnd = createParentWindow();
ok(parent_wnd != NULL, "Failed to create parent window!\n");
test_width();
test_curfocus();
test_cursel();
test_extendedstyle();
test_unicodeformat();
test_getset_item();
test_getset_tooltips();
test_adjustrect();
test_insert_focus();
test_delete_focus();
test_delete_selection();
test_removeimage();
test_TCM_SETITEMEXTRA();
test_TCS_OWNERDRAWFIXED();
test_WM_CONTEXTMENU();
test_create();
test_TCN_SELCHANGING();
test_TCM_GETROWCOUNT();
DestroyWindow(parent_wnd);
}