[COMCTL32_WINETEST] Sync with Wine Staging 4.18. CORE-16441

This commit is contained in:
Amine Khaldi 2019-10-26 22:52:00 +01:00
parent 5ddec3d944
commit 8addeea484
11 changed files with 1316 additions and 186 deletions

View file

@ -48,7 +48,8 @@ static BOOL (WINAPI *pImageList_Destroy)(HIMAGELIST);
#define ID_BUTTON 0x000e
#define COMBINED_SEQ_INDEX 0
#define NUM_MSG_SEQUENCES 1
#define PARENT_CD_SEQ_INDEX 1
#define NUM_MSG_SEQUENCES 2
static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
@ -160,11 +161,40 @@ static LRESULT CALLBACK button_subclass_proc(HWND hwnd, UINT message, WPARAM wPa
return ret;
}
static struct
{
DWORD button;
UINT line;
UINT state;
DWORD ret;
BOOL empty;
} test_cd;
#define set_test_cd_state(s) do { \
test_cd.state = (s); \
test_cd.empty = TRUE; \
test_cd.line = __LINE__; \
} while (0)
#define set_test_cd_ret(r) do { \
test_cd.ret = (r); \
test_cd.empty = TRUE; \
test_cd.line = __LINE__; \
} while (0)
static void disable_test_cd(void)
{
test_cd.line = 0;
}
static LRESULT WINAPI test_parent_wndproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static LONG defwndproc_counter = 0;
static LONG beginpaint_counter = 0;
static HDC cd_first_hdc;
struct message msg = { 0 };
NMCUSTOMDRAW *cd = (NMCUSTOMDRAW*)lParam;
NMBCDROPDOWN *bcd = (NMBCDROPDOWN*)lParam;
LRESULT ret;
if (ignore_message( message )) return 0;
@ -184,6 +214,76 @@ static LRESULT WINAPI test_parent_wndproc(HWND hwnd, UINT message, WPARAM wParam
add_message(sequences, COMBINED_SEQ_INDEX, &msg);
}
if (message == WM_NOTIFY && cd->hdr.code == NM_CUSTOMDRAW && test_cd.line)
{
/* Ignore an inconsistency across Windows versions */
UINT state = cd->uItemState & ~CDIS_SHOWKEYBOARDCUES;
/* Some Windows configurations paint twice with different DC */
if (test_cd.empty)
{
cd_first_hdc = cd->hdc;
test_cd.empty = FALSE;
}
ok_(__FILE__,test_cd.line)(!(cd->dwDrawStage & CDDS_ITEM),
"[%u] CDDS_ITEM is set\n", test_cd.button);
ok_(__FILE__,test_cd.line)(state == test_cd.state,
"[%u] expected uItemState %u, got %u\n", test_cd.button,
test_cd.state, state);
msg.message = message;
msg.flags = sent|parent|wparam|lparam|id|custdraw;
msg.wParam = wParam;
msg.lParam = lParam;
msg.id = NM_CUSTOMDRAW;
msg.stage = cd->dwDrawStage;
if (cd->hdc == cd_first_hdc)
add_message(sequences, PARENT_CD_SEQ_INDEX, &msg);
ret = test_cd.ret;
switch (msg.stage)
{
case CDDS_PREERASE:
ret &= ~CDRF_NOTIFYPOSTPAINT;
cd->dwItemSpec = 0xdeadbeef;
break;
case CDDS_PREPAINT:
ret &= ~CDRF_NOTIFYPOSTERASE;
break;
case CDDS_POSTERASE:
case CDDS_POSTPAINT:
ok_(__FILE__,test_cd.line)(cd->dwItemSpec == 0xdeadbeef,
"[%u] NMCUSTOMDRAW was not shared, stage %u\n", test_cd.button, msg.stage);
break;
}
return ret;
}
if (message == WM_NOTIFY && bcd->hdr.code == BCN_DROPDOWN)
{
UINT button = GetWindowLongW(bcd->hdr.hwndFrom, GWL_STYLE) & BS_TYPEMASK;
RECT rc;
GetClientRect(bcd->hdr.hwndFrom, &rc);
ok(bcd->hdr.hwndFrom != NULL, "Received BCN_DROPDOWN with no hwnd attached, wParam %lu id %lu\n",
wParam, bcd->hdr.idFrom);
ok(bcd->hdr.idFrom == wParam, "[%u] Mismatch between wParam (%lu) and idFrom (%lu)\n",
button, wParam, bcd->hdr.idFrom);
ok(EqualRect(&rc, &bcd->rcButton), "[%u] Wrong rcButton, expected %s got %s\n",
button, wine_dbgstr_rect(&rc), wine_dbgstr_rect(&bcd->rcButton));
msg.message = message;
msg.flags = sent|parent|wparam|lparam|id;
msg.wParam = wParam;
msg.lParam = lParam;
msg.id = BCN_DROPDOWN;
add_message(sequences, COMBINED_SEQ_INDEX, &msg);
return 0;
}
if (message == WM_PAINT)
{
PAINTSTRUCT ps;
@ -461,6 +561,60 @@ static const struct message setcheck_radio_redraw_seq[] =
{ 0 }
};
static const struct message empty_cd_seq[] = { { 0 } };
static const struct message pre_cd_seq[] =
{
{ WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREERASE },
{ 0 }
};
static const struct message pre_pre_cd_seq[] =
{
{ WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREERASE },
{ WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
{ 0 }
};
static const struct message pre_post_pre_cd_seq[] =
{
{ WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREERASE },
{ WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTERASE },
{ WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
{ 0 }
};
static const struct message pre_pre_post_cd_seq[] =
{
{ WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREERASE },
{ WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
{ WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT },
{ 0 }
};
static const struct message pre_post_pre_post_cd_seq[] =
{
{ WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREERASE },
{ WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTERASE },
{ WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
{ WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT },
{ 0 }
};
static const struct message bcn_dropdown_seq[] =
{
{ WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
{ BCM_SETDROPDOWNSTATE, sent|wparam|lparam|defwinproc, 1, 0 },
{ WM_NOTIFY, sent|parent|id, 0, 0, BCN_DROPDOWN },
{ BCM_SETDROPDOWNSTATE, sent|wparam|lparam|defwinproc, 0, 0 },
{ WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0xc0000000 },
{ WM_PAINT, sent },
{ WM_DRAWITEM, sent|parent|optional }, /* for owner draw button */
{ WM_PAINT, sent|optional }, /* sometimes sent rarely */
{ WM_DRAWITEM, sent|parent|optional },
{ 0 }
};
static HWND create_button(DWORD style, HWND parent)
{
HMENU menuid = 0;
@ -479,6 +633,13 @@ static HWND create_button(DWORD style, HWND parent)
static void test_button_messages(void)
{
enum cd_seq_type
{
cd_seq_empty,
cd_seq_normal,
cd_seq_optional
};
static const struct
{
DWORD style;
@ -489,55 +650,74 @@ static void test_button_messages(void)
const struct message *setstate;
const struct message *clearstate;
const struct message *setcheck;
enum cd_seq_type cd_setfocus_type;
enum cd_seq_type cd_setstyle_type;
enum cd_seq_type cd_setstate_type;
enum cd_seq_type cd_setcheck_type;
} button[] = {
{ BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
setfocus_seq, killfocus_seq, setstyle_seq,
setstate_seq, setstate_seq, setcheck_ignored_seq },
setstate_seq, setstate_seq, setcheck_ignored_seq,
cd_seq_normal, cd_seq_normal, cd_seq_normal, cd_seq_optional },
{ BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
setfocus_seq, killfocus_seq, setstyle_seq,
setstate_seq, setstate_seq, setcheck_ignored_seq },
setstate_seq, setstate_seq, setcheck_ignored_seq,
cd_seq_normal, cd_seq_normal, cd_seq_normal, cd_seq_optional },
{ BS_CHECKBOX, DLGC_BUTTON,
setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
setstate_static_seq, setstate_static_seq, setcheck_static_seq },
setstate_static_seq, setstate_static_seq, setcheck_static_seq,
cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_optional },
{ BS_AUTOCHECKBOX, DLGC_BUTTON,
setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
setstate_static_seq, setstate_static_seq, setcheck_static_seq },
setstate_static_seq, setstate_static_seq, setcheck_static_seq,
cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_optional },
{ BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
setstate_static_seq, setstate_static_seq, setcheck_radio_redraw_seq },
setstate_static_seq, setstate_static_seq, setcheck_radio_redraw_seq,
cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_optional },
{ BS_3STATE, DLGC_BUTTON,
setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
setstate_static_seq, setstate_static_seq, setcheck_static_seq },
setstate_static_seq, setstate_static_seq, setcheck_static_seq,
cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_optional },
{ BS_AUTO3STATE, DLGC_BUTTON,
setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
setstate_static_seq, setstate_static_seq, setcheck_static_seq },
setstate_static_seq, setstate_static_seq, setcheck_static_seq,
cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_optional },
{ BS_GROUPBOX, DLGC_STATIC,
setfocus_groupbox_seq, killfocus_static_seq, setstyle_static_seq,
setstate_static_seq, setstate_static_seq, setcheck_ignored_seq },
setstate_static_seq, setstate_static_seq, setcheck_ignored_seq,
cd_seq_empty, cd_seq_empty, cd_seq_empty, cd_seq_empty },
{ BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
setfocus_seq, killfocus_seq, setstyle_user_seq,
setstate_user_seq, clearstate_seq, setcheck_ignored_seq },
setstate_user_seq, clearstate_seq, setcheck_ignored_seq,
cd_seq_normal, cd_seq_empty, cd_seq_empty, cd_seq_empty },
{ BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
setstate_static_seq, setstate_static_seq, setcheck_radio_redraw_seq },
setstate_static_seq, setstate_static_seq, setcheck_radio_redraw_seq,
cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_optional },
{ BS_OWNERDRAW, DLGC_BUTTON,
setfocus_ownerdraw_seq, killfocus_ownerdraw_seq, setstyle_ownerdraw_seq,
setstate_ownerdraw_seq, clearstate_ownerdraw_seq, setcheck_ignored_seq },
setstate_ownerdraw_seq, clearstate_ownerdraw_seq, setcheck_ignored_seq,
cd_seq_empty, cd_seq_empty, cd_seq_empty, cd_seq_empty },
{ BS_SPLITBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON | DLGC_WANTARROWS,
setfocus_seq, killfocus_seq, setstyle_seq,
setstate_seq, setstate_seq, setcheck_ignored_seq },
setstate_seq, setstate_seq, setcheck_ignored_seq,
cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_empty },
{ BS_DEFSPLITBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON | DLGC_WANTARROWS,
setfocus_seq, killfocus_seq, setstyle_seq,
setstate_seq, setstate_seq, setcheck_ignored_seq },
setstate_seq, setstate_seq, setcheck_ignored_seq,
cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_empty },
{ BS_COMMANDLINK, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
setfocus_seq, killfocus_seq, setstyle_seq,
setstate_seq, setstate_seq, setcheck_ignored_seq },
setstate_seq, setstate_seq, setcheck_ignored_seq,
cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_empty },
{ BS_DEFCOMMANDLINK, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
setfocus_seq, killfocus_seq, setstyle_seq,
setstate_seq, setstate_seq, setcheck_ignored_seq },
setstate_seq, setstate_seq, setcheck_ignored_seq,
cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_empty }
};
LOGFONTA logfont = { 0 };
const struct message *seq;
const struct message *seq, *cd_seq;
HFONT zfont, hfont2;
unsigned int i;
HWND hwnd, parent;
@ -565,6 +745,11 @@ static void test_button_messages(void)
hfont2 = CreateFontIndirectA(&logfont);
ok(hfont2 != NULL, "Failed to create Tahoma font\n");
#define check_cd_seq(type, context) do { \
if (button[i].type != cd_seq_optional || !test_cd.empty) \
ok_sequence(sequences, PARENT_CD_SEQ_INDEX, cd_seq, "[CustomDraw] " context, FALSE); \
} while(0)
for (i = 0; i < ARRAY_SIZE(button); i++)
{
HFONT prevfont, hfont;
@ -572,6 +757,7 @@ static void test_button_messages(void)
DWORD style, state;
HDC hdc;
test_cd.button = button[i].style;
hwnd = create_button(button[i].style, parent);
ok(hwnd != NULL, "Failed to create a button.\n");
@ -599,27 +785,35 @@ static void test_button_messages(void)
SetFocus(0);
flush_events();
SetFocus(0);
cd_seq = (button[i].cd_setfocus_type == cd_seq_empty) ? empty_cd_seq : pre_pre_cd_seq;
flush_sequences(sequences, NUM_MSG_SEQUENCES);
set_test_cd_ret(CDRF_DODEFAULT);
set_test_cd_state(CDIS_FOCUS);
todo = button[i].style != BS_OWNERDRAW;
ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
SetFocus(hwnd);
SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setfocus, "SetFocus(hwnd) on a button", todo);
ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
check_cd_seq(cd_setfocus_type, "SetFocus(hwnd)");
todo = button[i].style == BS_OWNERDRAW;
set_test_cd_state(0);
SetFocus(0);
SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].killfocus, "SetFocus(0) on a button", todo);
ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].killfocus, "SetFocus(0) on a button", FALSE);
check_cd_seq(cd_setfocus_type, "SetFocus(0)");
ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
cd_seq = (button[i].cd_setstyle_type == cd_seq_empty) ? empty_cd_seq : pre_pre_cd_seq;
set_test_cd_state(0);
SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
todo = button[i].style == BS_OWNERDRAW;
ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setstyle, "BM_SETSTYLE on a button", todo);
check_cd_seq(cd_setstyle_type, "BM_SETSTYLE");
style = GetWindowLongA(hwnd, GWL_STYLE);
style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
@ -629,12 +823,15 @@ static void test_button_messages(void)
state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
ok(state == 0, "expected state 0, got %04x\n", state);
cd_seq = (button[i].cd_setstate_type == cd_seq_empty) ? empty_cd_seq : pre_pre_cd_seq;
flush_sequences(sequences, NUM_MSG_SEQUENCES);
set_test_cd_state(CDIS_SELECTED);
SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
check_cd_seq(cd_setstate_type, "BM_SETSTATE/TRUE");
state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
ok(state == BST_PUSHED, "expected state 0x0004, got %04x\n", state);
@ -644,11 +841,13 @@ static void test_button_messages(void)
ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
set_test_cd_state(0);
SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
check_cd_seq(cd_setstate_type, "BM_SETSTATE/FALSE");
state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
ok(state == 0, "expected state 0, got %04x\n", state);
@ -660,7 +859,9 @@ static void test_button_messages(void)
state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
cd_seq = (button[i].cd_setcheck_type == cd_seq_empty) ? empty_cd_seq : pre_pre_cd_seq;
flush_sequences(sequences, NUM_MSG_SEQUENCES);
set_test_cd_state(0);
if (button[i].style == BS_RADIOBUTTON ||
button[i].style == BS_AUTORADIOBUTTON)
@ -674,6 +875,7 @@ static void test_button_messages(void)
SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
ok_sequence(sequences, COMBINED_SEQ_INDEX, seq, "BM_SETCHECK on a button", FALSE);
check_cd_seq(cd_setcheck_type, "BM_SETCHECK");
state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
@ -683,11 +885,13 @@ static void test_button_messages(void)
ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
set_test_cd_state(0);
SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setcheck, "BM_SETCHECK on a button", FALSE);
check_cd_seq(cd_setcheck_type, "BM_SETCHECK");
state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
if (button[i].style == BS_PUSHBUTTON ||
@ -735,9 +939,60 @@ static void test_button_messages(void)
DeleteDC(hdc);
/* Test Custom Draw return values */
if (button[i].cd_setfocus_type != cd_seq_empty &&
broken(button[i].style != BS_USERBUTTON) /* WinXP */)
{
static const struct
{
const char *context;
LRESULT val;
const struct message *seq;
} ret[] = {
{ "CDRF_DODEFAULT", CDRF_DODEFAULT, pre_pre_cd_seq },
{ "CDRF_DOERASE", CDRF_DOERASE, pre_pre_cd_seq },
{ "CDRF_SKIPDEFAULT", CDRF_SKIPDEFAULT, pre_cd_seq },
{ "CDRF_SKIPDEFAULT | CDRF_NOTIFYPOSTERASE | CDRF_NOTIFYPOSTPAINT",
CDRF_SKIPDEFAULT | CDRF_NOTIFYPOSTERASE | CDRF_NOTIFYPOSTPAINT, pre_cd_seq },
{ "CDRF_NOTIFYPOSTERASE", CDRF_NOTIFYPOSTERASE, pre_post_pre_cd_seq },
{ "CDRF_NOTIFYPOSTPAINT", CDRF_NOTIFYPOSTPAINT, pre_pre_post_cd_seq },
{ "CDRF_NOTIFYPOSTERASE | CDRF_NOTIFYPOSTPAINT",
CDRF_NOTIFYPOSTERASE | CDRF_NOTIFYPOSTPAINT, pre_post_pre_post_cd_seq },
};
UINT k;
for (k = 0; k < ARRAY_SIZE(ret); k++)
{
disable_test_cd();
SetFocus(0);
set_test_cd_ret(ret[k].val);
set_test_cd_state(CDIS_FOCUS);
SetFocus(hwnd);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
if (button[i].cd_setfocus_type != cd_seq_optional || !test_cd.empty)
ok_sequence(sequences, PARENT_CD_SEQ_INDEX, ret[k].seq, ret[k].context, FALSE);
}
}
disable_test_cd();
if (!broken(LOBYTE(LOWORD(GetVersion())) < 6)) /* not available pre-Vista */
{
/* Send down arrow key to make the buttons send the drop down notification */
flush_sequences(sequences, NUM_MSG_SEQUENCES);
SendMessageW(hwnd, WM_KEYDOWN, VK_DOWN, 0);
SendMessageW(hwnd, WM_KEYUP, VK_DOWN, 0xc0000000);
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
ok_sequence(sequences, COMBINED_SEQ_INDEX, bcn_dropdown_seq, "BCN_DROPDOWN from the button", FALSE);
}
DestroyWindow(hwnd);
}
#undef check_cd_seq
DeleteObject(hfont2);
DestroyWindow(parent);
@ -1228,6 +1483,214 @@ static void register_parent_class(void)
RegisterClassA(&cls);
}
static void test_bcm_splitinfo(HWND hwnd)
{
UINT button = GetWindowLongA(hwnd, GWL_STYLE) & BS_TYPEMASK;
int glyph_size = GetSystemMetrics(SM_CYMENUCHECK);
int border_w = GetSystemMetrics(SM_CXEDGE) * 2;
BUTTON_SPLITINFO info, dummy;
HIMAGELIST img;
BOOL ret;
memset(&info, 0xCC, sizeof(info));
info.mask = 0;
memcpy(&dummy, &info, sizeof(info));
ret = SendMessageA(hwnd, BCM_GETSPLITINFO, 0, (LPARAM)&info);
if (ret != TRUE)
{
static BOOL once;
if (!once)
win_skip("BCM_GETSPLITINFO message is unavailable. Skipping related tests\n"); /* Pre-Vista */
once = TRUE;
return;
}
ok(!memcmp(&info, &dummy, sizeof(info)), "[%u] split info struct was changed with mask = 0\n", button);
ret = SendMessageA(hwnd, BCM_GETSPLITINFO, 0, 0);
ok(ret == FALSE, "[%u] expected FALSE, got %d\n", button, ret);
ret = SendMessageA(hwnd, BCM_SETSPLITINFO, 0, 0);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
info.mask = BCSIF_GLYPH | BCSIF_SIZE | BCSIF_STYLE;
ret = SendMessageA(hwnd, BCM_GETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
ok(info.mask == (BCSIF_GLYPH | BCSIF_SIZE | BCSIF_STYLE), "[%u] wrong mask, got %u\n", button, info.mask);
ok(info.himlGlyph == (HIMAGELIST)0x36, "[%u] expected 0x36 default glyph, got 0x%p\n", button, info.himlGlyph);
ok(info.uSplitStyle == BCSS_STRETCH, "[%u] expected 0x%08x default style, got 0x%08x\n", button, BCSS_STRETCH, info.uSplitStyle);
ok(info.size.cx == glyph_size, "[%u] expected %d default size.cx, got %d\n", button, glyph_size, info.size.cx);
ok(info.size.cy == 0, "[%u] expected 0 default size.cy, got %d\n", button, info.size.cy);
info.mask = BCSIF_SIZE;
info.size.cx = glyph_size + 7;
info.size.cy = 0;
ret = SendMessageA(hwnd, BCM_SETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
info.size.cx = info.size.cy = 0xdeadbeef;
ret = SendMessageA(hwnd, BCM_GETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
ok(info.mask == BCSIF_SIZE, "[%u] wrong mask, got %u\n", button, info.mask);
ok(info.size.cx == glyph_size + 7, "[%u] expected %d, got %d\n", button, glyph_size + 7, info.size.cx);
ok(info.size.cy == 0, "[%u] expected 0, got %d\n", button, info.size.cy);
/* Invalid size.cx resets it to default glyph size, while size.cy is stored */
info.size.cx = 0;
info.size.cy = -20;
ret = SendMessageA(hwnd, BCM_SETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
info.size.cx = info.size.cy = 0xdeadbeef;
ret = SendMessageA(hwnd, BCM_GETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
ok(info.mask == BCSIF_SIZE, "[%u] wrong mask, got %u\n", button, info.mask);
ok(info.size.cx == glyph_size, "[%u] expected %d, got %d\n", button, glyph_size, info.size.cx);
ok(info.size.cy == -20, "[%u] expected -20, got %d\n", button, info.size.cy);
info.size.cx = -glyph_size - 7;
info.size.cy = -10;
ret = SendMessageA(hwnd, BCM_SETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
info.size.cx = info.size.cy = 0xdeadbeef;
ret = SendMessageA(hwnd, BCM_GETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
ok(info.mask == BCSIF_SIZE, "[%u] wrong mask, got %u\n", button, info.mask);
ok(info.size.cx == glyph_size, "[%u] expected %d, got %d\n", button, glyph_size, info.size.cx);
ok(info.size.cy == -10, "[%u] expected -10, got %d\n", button, info.size.cy);
/* Set to a valid size other than glyph_size */
info.mask = BCSIF_SIZE;
info.size.cx = glyph_size + 7;
info.size.cy = 11;
ret = SendMessageA(hwnd, BCM_SETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
info.size.cx = info.size.cy = 0xdeadbeef;
ret = SendMessageA(hwnd, BCM_GETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
ok(info.mask == BCSIF_SIZE, "[%u] wrong mask, got %u\n", button, info.mask);
ok(info.size.cx == glyph_size + 7, "[%u] expected %d, got %d\n", button, glyph_size + 7, info.size.cx);
ok(info.size.cy == 11, "[%u] expected 11, got %d\n", button, info.size.cy);
/* Change the glyph, size.cx should be automatically adjusted and size.cy set to 0 */
dummy.mask = BCSIF_GLYPH;
dummy.himlGlyph = (HIMAGELIST)0x35;
ret = SendMessageA(hwnd, BCM_SETSPLITINFO, 0, (LPARAM)&dummy);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
info.mask = BCSIF_GLYPH | BCSIF_SIZE;
ret = SendMessageA(hwnd, BCM_GETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
ok(info.mask == (BCSIF_GLYPH | BCSIF_SIZE), "[%u] wrong mask, got %u\n", button, info.mask);
ok(info.himlGlyph == (HIMAGELIST)0x35, "[%u] expected 0x35, got %p\n", button, info.himlGlyph);
ok(info.size.cx == glyph_size, "[%u] expected %d, got %d\n", button, glyph_size, info.size.cx);
ok(info.size.cy == 0, "[%u] expected 0, got %d\n", button, info.size.cy);
/* Unless the size is specified manually */
dummy.mask = BCSIF_GLYPH | BCSIF_SIZE;
dummy.himlGlyph = (HIMAGELIST)0x34;
dummy.size.cx = glyph_size + 11;
dummy.size.cy = 7;
ret = SendMessageA(hwnd, BCM_SETSPLITINFO, 0, (LPARAM)&dummy);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
ret = SendMessageA(hwnd, BCM_GETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
ok(info.mask == (BCSIF_GLYPH | BCSIF_SIZE), "[%u] wrong mask, got %u\n", button, info.mask);
ok(info.himlGlyph == (HIMAGELIST)0x34, "[%u] expected 0x34, got %p\n", button, info.himlGlyph);
ok(info.size.cx == glyph_size + 11, "[%u] expected %d, got %d\n", button, glyph_size, info.size.cx);
ok(info.size.cy == 7, "[%u] expected 7, got %d\n", button, info.size.cy);
/* Add the BCSS_IMAGE style manually with the wrong BCSIF_GLYPH mask, should treat it as invalid image */
info.mask = BCSIF_GLYPH | BCSIF_STYLE;
info.himlGlyph = (HIMAGELIST)0x37;
info.uSplitStyle = BCSS_IMAGE;
ret = SendMessageA(hwnd, BCM_SETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
info.mask |= BCSIF_SIZE;
ret = SendMessageA(hwnd, BCM_GETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
ok(info.mask == (BCSIF_GLYPH | BCSIF_STYLE | BCSIF_SIZE), "[%u] wrong mask, got %u\n", button, info.mask);
ok(info.himlGlyph == (HIMAGELIST)0x37, "[%u] expected 0x37, got %p\n", button, info.himlGlyph);
ok(info.uSplitStyle == BCSS_IMAGE, "[%u] expected 0x%08x style, got 0x%08x\n", button, BCSS_IMAGE, info.uSplitStyle);
ok(info.size.cx == border_w, "[%u] expected %d, got %d\n", button, border_w, info.size.cx);
ok(info.size.cy == 0, "[%u] expected 0, got %d\n", button, info.size.cy);
/* Change the size to prevent ambiguity */
dummy.mask = BCSIF_SIZE;
dummy.size.cx = glyph_size + 5;
dummy.size.cy = 4;
ret = SendMessageA(hwnd, BCM_SETSPLITINFO, 0, (LPARAM)&dummy);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
ret = SendMessageA(hwnd, BCM_GETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
ok(info.mask == (BCSIF_GLYPH | BCSIF_STYLE | BCSIF_SIZE), "[%u] wrong mask, got %u\n", button, info.mask);
ok(info.himlGlyph == (HIMAGELIST)0x37, "[%u] expected 0x37, got %p\n", button, info.himlGlyph);
ok(info.uSplitStyle == BCSS_IMAGE, "[%u] expected 0x%08x style, got 0x%08x\n", button, BCSS_IMAGE, info.uSplitStyle);
ok(info.size.cx == glyph_size + 5, "[%u] expected %d, got %d\n", button, glyph_size + 5, info.size.cx);
ok(info.size.cy == 4, "[%u] expected 4, got %d\n", button, info.size.cy);
/* Now remove the BCSS_IMAGE style manually with the wrong BCSIF_IMAGE mask */
info.mask = BCSIF_IMAGE | BCSIF_STYLE;
info.himlGlyph = (HIMAGELIST)0x35;
info.uSplitStyle = BCSS_STRETCH;
ret = SendMessageA(hwnd, BCM_SETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
info.mask |= BCSIF_SIZE;
ret = SendMessageA(hwnd, BCM_GETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
ok(info.mask == (BCSIF_IMAGE | BCSIF_STYLE | BCSIF_SIZE), "[%u] wrong mask, got %u\n", button, info.mask);
ok(info.himlGlyph == (HIMAGELIST)0x35, "[%u] expected 0x35, got %p\n", button, info.himlGlyph);
ok(info.uSplitStyle == BCSS_STRETCH, "[%u] expected 0x%08x style, got 0x%08x\n", button, BCSS_STRETCH, info.uSplitStyle);
ok(info.size.cx == glyph_size, "[%u] expected %d, got %d\n", button, glyph_size, info.size.cx);
ok(info.size.cy == 0, "[%u] expected 0, got %d\n", button, info.size.cy);
/* Add a proper valid image, the BCSS_IMAGE style should be set automatically */
img = pImageList_Create(42, 33, ILC_COLOR, 1, 1);
ok(img != NULL, "[%u] failed to create ImageList\n", button);
info.mask = BCSIF_IMAGE;
info.himlGlyph = img;
ret = SendMessageA(hwnd, BCM_SETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
info.mask |= BCSIF_STYLE | BCSIF_SIZE;
ret = SendMessageA(hwnd, BCM_GETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
ok(info.mask == (BCSIF_IMAGE | BCSIF_STYLE | BCSIF_SIZE), "[%u] wrong mask, got %u\n", button, info.mask);
ok(info.himlGlyph == img, "[%u] expected %p, got %p\n", button, img, info.himlGlyph);
ok(info.uSplitStyle == (BCSS_IMAGE | BCSS_STRETCH), "[%u] expected 0x%08x style, got 0x%08x\n", button, BCSS_IMAGE | BCSS_STRETCH, info.uSplitStyle);
ok(info.size.cx == 42 + border_w, "[%u] expected %d, got %d\n", button, 42 + border_w, info.size.cx);
ok(info.size.cy == 0, "[%u] expected 0, got %d\n", button, info.size.cy);
pImageList_Destroy(img);
dummy.mask = BCSIF_SIZE;
dummy.size.cx = glyph_size + 5;
dummy.size.cy = 4;
ret = SendMessageA(hwnd, BCM_SETSPLITINFO, 0, (LPARAM)&dummy);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
/* Change it to a glyph; when both specified, BCSIF_GLYPH takes priority */
info.mask = BCSIF_GLYPH | BCSIF_IMAGE;
info.himlGlyph = (HIMAGELIST)0x37;
ret = SendMessageA(hwnd, BCM_SETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
info.mask |= BCSIF_STYLE | BCSIF_SIZE;
ret = SendMessageA(hwnd, BCM_GETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
ok(info.mask == (BCSIF_GLYPH | BCSIF_IMAGE | BCSIF_STYLE | BCSIF_SIZE), "[%u] wrong mask, got %u\n", button, info.mask);
ok(info.himlGlyph == (HIMAGELIST)0x37, "[%u] expected 0x37, got %p\n", button, info.himlGlyph);
ok(info.uSplitStyle == BCSS_STRETCH, "[%u] expected 0x%08x style, got 0x%08x\n", button, BCSS_STRETCH, info.uSplitStyle);
ok(info.size.cx == glyph_size, "[%u] expected %d, got %d\n", button, glyph_size, info.size.cx);
ok(info.size.cy == 0, "[%u] expected 0, got %d\n", button, info.size.cy);
/* Try a NULL image */
info.mask = BCSIF_IMAGE;
info.himlGlyph = NULL;
ret = SendMessageA(hwnd, BCM_SETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
info.mask |= BCSIF_STYLE | BCSIF_SIZE;
ret = SendMessageA(hwnd, BCM_GETSPLITINFO, 0, (LPARAM)&info);
ok(ret == TRUE, "[%u] expected TRUE, got %d\n", button, ret);
ok(info.mask == (BCSIF_IMAGE | BCSIF_STYLE | BCSIF_SIZE), "[%u] wrong mask, got %u\n", button, info.mask);
ok(info.himlGlyph == NULL, "[%u] expected NULL, got %p\n", button, info.himlGlyph);
ok(info.uSplitStyle == (BCSS_IMAGE | BCSS_STRETCH), "[%u] expected 0x%08x style, got 0x%08x\n", button, BCSS_IMAGE | BCSS_STRETCH, info.uSplitStyle);
ok(info.size.cx == border_w, "[%u] expected %d, got %d\n", button, border_w, info.size.cx);
ok(info.size.cy == 0, "[%u] expected 0, got %d\n", button, info.size.cy);
}
static void test_button_data(void)
{
static const DWORD styles[] =
@ -1280,6 +1743,9 @@ static void test_button_data(void)
ok(desc->style == (WS_CHILD | BS_NOTIFY | styles[i]), "Unexpected 'style' field.\n");
}
/* Data set and retrieved by these messages is valid for all buttons */
test_bcm_splitinfo(hwnd);
DestroyWindow(hwnd);
}
@ -1431,14 +1897,31 @@ static void test_bcm_get_ideal_size(void)
{
static const char *button_text2 = "WWWW\nWWWW";
static const char *button_text = "WWWW";
static const WCHAR button_note_short[] = { 'W',0 };
static const WCHAR button_note_long[] = { 'W','W','W','W','W','W','W','W','W','W','W','W','W','W','W','W',0 };
static const WCHAR button_note_wordy[] = { 'T','h','i','s',' ','i','s',' ','a',' ','l','o','n','g',' ','n','o','t','e',' ','f','o','r',' ','t','h','e',' ','b','u','t','t','o','n',',',' ',
'w','i','t','h',' ','m','a','n','y',' ','w','o','r','d','s',',',' ','w','h','i','c','h',' ','s','h','o','u','l','d',' ','b','e',' ',
'o','v','e','r','a','l','l',' ','l','o','n','g','e','r',' ','t','h','a','n',' ','t','h','e',' ','t','e','x','t',' ','(','g','i','v','e','n',' ',
't','h','e',' ','s','m','a','l','l','e','r',' ','f','o','n','t',')',' ','a','n','d',' ','t','h','u','s',' ','w','r','a','p','.',0 };
static const DWORD imagelist_aligns[] = {BUTTON_IMAGELIST_ALIGN_LEFT, BUTTON_IMAGELIST_ALIGN_RIGHT,
BUTTON_IMAGELIST_ALIGN_TOP, BUTTON_IMAGELIST_ALIGN_BOTTOM,
BUTTON_IMAGELIST_ALIGN_CENTER};
static const DWORD aligns[] = {0, BS_TOP, BS_LEFT, BS_RIGHT, BS_BOTTOM,
BS_CENTER, BS_VCENTER, BS_RIGHTBUTTON, WS_EX_RIGHT};
DWORD default_style = WS_TABSTOP | WS_POPUP | WS_VISIBLE;
const LONG client_width = 400, client_height = 200;
LONG image_width, height, line_count, text_width;
const LONG client_width = 400, client_height = 200, extra_width = 123, large_height = 500;
struct
{
DWORD style;
LONG extra_width;
} pushtype[] =
{
{ BS_PUSHBUTTON, 0 },
{ BS_DEFPUSHBUTTON, 0 },
{ BS_SPLITBUTTON, extra_width * 2 + GetSystemMetrics(SM_CXEDGE) },
{ BS_DEFSPLITBUTTON, extra_width * 2 + GetSystemMetrics(SM_CXEDGE) }
};
LONG image_width = 48, height = 48, line_count, text_width;
HFONT hfont, prev_font;
DWORD style, type;
BOOL ret;
@ -1453,7 +1936,7 @@ static void test_bcm_get_ideal_size(void)
HIMAGELIST himl;
BUTTON_IMAGELIST biml = {0};
RECT rect;
INT i, j;
INT i, j, k;
/* Check for NULL pointer handling */
hwnd = CreateWindowA(WC_BUTTONA, button_text, BS_PUSHBUTTON | default_style, 0, 0, client_width, client_height,
@ -1496,34 +1979,49 @@ static void test_bcm_get_ideal_size(void)
/* Tests for image placements */
/* Prepare bitmap */
image_width = 48;
height = 48;
hdc = GetDC(0);
hmask = CreateCompatibleBitmap(hdc, image_width, height);
hbmp = CreateCompatibleBitmap(hdc, image_width, height);
himl = pImageList_Create(image_width, height, ILC_COLOR, 1, 1);
pImageList_Add(himl, hbmp, 0);
#define set_split_info(hwnd) do { \
BUTTON_SPLITINFO _info; \
int _ret; \
_info.mask = BCSIF_SIZE; \
_info.size.cx = extra_width; \
_info.size.cy = large_height; \
_ret = SendMessageA(hwnd, BCM_SETSPLITINFO, 0, (LPARAM)&_info); \
ok(_ret == TRUE, "Expected BCM_SETSPLITINFO message to return true\n"); \
} while (0)
for (k = 0; k < ARRAY_SIZE(pushtype); k++)
{
/* Only bitmap for push button, ideal size should be enough for image and text */
hwnd = CreateWindowA(WC_BUTTONA, button_text, BS_DEFPUSHBUTTON | BS_BITMAP | default_style, 0, 0, client_width,
hwnd = CreateWindowA(WC_BUTTONA, button_text, pushtype[k].style | BS_BITMAP | default_style, 0, 0, client_width,
client_height, NULL, NULL, 0, NULL);
ok(hwnd != NULL, "Expect hwnd not NULL\n");
set_split_info(hwnd);
SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
ZeroMemory(&size, sizeof(size));
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret, "Expect BCM_GETIDEALSIZE message to return true\n");
/* Ideal size contains text rect even show bitmap only */
ok((size.cx >= image_width + text_width && size.cy >= max(height, tm.tmHeight)),
"Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size.cx, image_width + text_width,
size.cy, max(height, tm.tmHeight));
ok(size.cx >= image_width + text_width + pushtype[k].extra_width && size.cy >= max(height, tm.tmHeight),
"Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size.cx,
image_width + text_width + pushtype[k].extra_width, size.cy, max(height, tm.tmHeight));
ok(size.cy < large_height, "Expect ideal cy %d < %d\n", size.cy, large_height);
DestroyWindow(hwnd);
/* Image alignments when button has bitmap and text*/
for (i = 0; i < ARRAY_SIZE(aligns); i++)
for (j = 0; j < ARRAY_SIZE(aligns); j++)
{
style = BS_DEFPUSHBUTTON | default_style | aligns[i] | aligns[j];
style = pushtype[k].style | default_style | aligns[i] | aligns[j];
hwnd = CreateWindowA(WC_BUTTONA, button_text, style, 0, 0, client_width, client_height, NULL, NULL, 0, NULL);
ok(hwnd != NULL, "Expect hwnd not NULL\n");
set_split_info(hwnd);
SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
ZeroMemory(&size, sizeof(size));
@ -1531,42 +2029,44 @@ static void test_bcm_get_ideal_size(void)
ok(ret, "Expect BCM_GETIDEALSIZE message to return true\n");
if (!(style & (BS_CENTER | BS_VCENTER)) || ((style & BS_CENTER) && (style & BS_CENTER) != BS_CENTER)
|| !(style & BS_VCENTER) || (style & BS_VCENTER) == BS_VCENTER)
ok((size.cx >= image_width + text_width && size.cy >= max(height, tm.tmHeight)),
ok(size.cx >= image_width + text_width + pushtype[k].extra_width && size.cy >= max(height, tm.tmHeight),
"Style: 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n", style, size.cx,
image_width + text_width, size.cy, max(height, tm.tmHeight));
image_width + text_width + pushtype[k].extra_width, size.cy, max(height, tm.tmHeight));
else
ok((size.cx >= max(text_width, height) && size.cy >= height + tm.tmHeight),
ok(size.cx >= max(text_width, height) + pushtype[k].extra_width && size.cy >= height + tm.tmHeight,
"Style: 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n", style, size.cx,
max(text_width, height), size.cy, height + tm.tmHeight);
max(text_width, height) + pushtype[k].extra_width, size.cy, height + tm.tmHeight);
ok(size.cy < large_height, "Expect ideal cy %d < %d\n", size.cy, large_height);
DestroyWindow(hwnd);
}
/* Image list alignments */
himl = pImageList_Create(image_width, height, ILC_COLOR, 1, 1);
pImageList_Add(himl, hbmp, 0);
biml.himl = himl;
for (i = 0; i < ARRAY_SIZE(imagelist_aligns); i++)
{
biml.uAlign = imagelist_aligns[i];
hwnd = CreateWindowA(WC_BUTTONA, button_text, BS_DEFPUSHBUTTON | default_style, 0, 0, client_width,
hwnd = CreateWindowA(WC_BUTTONA, button_text, pushtype[k].style | default_style, 0, 0, client_width,
client_height, NULL, NULL, 0, NULL);
ok(hwnd != NULL, "Expect hwnd not NULL\n");
set_split_info(hwnd);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
SendMessageA(hwnd, BCM_SETIMAGELIST, 0, (LPARAM)&biml);
ZeroMemory(&size, sizeof(size));
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret, "Expect BCM_GETIDEALSIZE message to return true\n");
if (biml.uAlign == BUTTON_IMAGELIST_ALIGN_TOP || biml.uAlign == BUTTON_IMAGELIST_ALIGN_BOTTOM)
ok((size.cx >= max(text_width, height) && size.cy >= height + tm.tmHeight),
ok(size.cx >= max(text_width, height) + pushtype[k].extra_width && size.cy >= height + tm.tmHeight,
"Align:%d expect ideal cx %d >= %d and ideal cy %d >= %d\n", biml.uAlign, size.cx,
max(text_width, height), size.cy, height + tm.tmHeight);
max(text_width, height) + pushtype[k].extra_width, size.cy, height + tm.tmHeight);
else if (biml.uAlign == BUTTON_IMAGELIST_ALIGN_LEFT || biml.uAlign == BUTTON_IMAGELIST_ALIGN_RIGHT)
ok((size.cx >= image_width + text_width && size.cy >= max(height, tm.tmHeight)),
ok(size.cx >= image_width + text_width + pushtype[k].extra_width && size.cy >= max(height, tm.tmHeight),
"Align:%d expect ideal cx %d >= %d and ideal cy %d >= %d\n", biml.uAlign, size.cx,
image_width + text_width, size.cy, max(height, tm.tmHeight));
image_width + text_width + pushtype[k].extra_width, size.cy, max(height, tm.tmHeight));
else
ok(size.cx >= image_width && size.cy >= height, "Align:%d expect ideal cx %d >= %d and ideal cy %d >= %d\n",
biml.uAlign, size.cx, image_width, size.cy, height);
ok(size.cx >= image_width + pushtype[k].extra_width && size.cy >= height,
"Align:%d expect ideal cx %d >= %d and ideal cy %d >= %d\n",
biml.uAlign, size.cx, image_width + pushtype[k].extra_width, size.cy, height);
ok(size.cy < large_height, "Expect ideal cy %d < %d\n", size.cy, large_height);
DestroyWindow(hwnd);
}
@ -1579,33 +2079,41 @@ static void test_bcm_get_ideal_size(void)
hicon = CreateIconIndirect(&icon_info);
/* Only icon, ideal size should be enough for image and text */
hwnd = CreateWindowA(WC_BUTTONA, button_text, BS_DEFPUSHBUTTON | BS_ICON | default_style, 0, 0, client_width,
hwnd = CreateWindowA(WC_BUTTONA, button_text, pushtype[k].style | BS_ICON | default_style, 0, 0, client_width,
client_height, NULL, NULL, 0, NULL);
ok(hwnd != NULL, "Expect hwnd not NULL\n");
set_split_info(hwnd);
SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
ZeroMemory(&size, sizeof(size));
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret, "Expect BCM_GETIDEALSIZE message to return true\n");
/* Ideal size contains text rect even show icons only */
ok((size.cx >= image_width + text_width && size.cy >= max(height, tm.tmHeight)),
"Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size.cx, image_width + text_width, size.cy,
max(height, tm.tmHeight));
ok(size.cx >= image_width + text_width + pushtype[k].extra_width && size.cy >= max(height, tm.tmHeight),
"Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size.cx,
image_width + text_width + pushtype[k].extra_width, size.cy, max(height, tm.tmHeight));
ok(size.cy < large_height, "Expect ideal cy %d < %d\n", size.cy, large_height);
DestroyWindow(hwnd);
/* Show icon and text */
hwnd = CreateWindowA(WC_BUTTONA, button_text, BS_DEFPUSHBUTTON | default_style, 0, 0, client_width,
hwnd = CreateWindowA(WC_BUTTONA, button_text, pushtype[k].style | default_style, 0, 0, client_width,
client_height, NULL, NULL, 0, NULL);
ok(hwnd != NULL, "Expect hwnd not NULL\n");
set_split_info(hwnd);
SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
ZeroMemory(&size, sizeof(size));
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret, "Expect BCM_GETIDEALSIZE message to return true\n");
ok((size.cx >= image_width + text_width && size.cy >= max(height, tm.tmHeight)),
"Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size.cx, image_width + text_width, size.cy,
max(height, tm.tmHeight));
ok(size.cx >= image_width + text_width + pushtype[k].extra_width && size.cy >= max(height, tm.tmHeight),
"Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size.cx,
image_width + text_width + pushtype[k].extra_width, size.cy, max(height, tm.tmHeight));
ok(size.cy < large_height, "Expect ideal cy %d < %d\n", size.cy, large_height);
DestroyWindow(hwnd);
DestroyIcon(hicon);
}
#undef set_split_info
/* Checkbox */
/* Both bitmap and text for checkbox, ideal size is only enough for text because it doesn't support image(but not image list)*/
@ -1667,7 +2175,7 @@ static void test_bcm_get_ideal_size(void)
if (type == BS_COMMANDLINK || type == BS_DEFCOMMANDLINK)
{
todo_wine ok((size.cx == 0 && size.cy > 0), "Style 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n",
ok((size.cx == 0 && size.cy > 0), "Style 0x%08x expect ideal cx %d == %d and ideal cy %d > %d\n",
style, size.cx, 0, size.cy, 0);
}
else
@ -1704,8 +2212,8 @@ static void test_bcm_get_ideal_size(void)
}
else if (type == BS_COMMANDLINK || type == BS_DEFCOMMANDLINK)
{
todo_wine ok((size.cx == 0 && size.cy > 0),
"Style 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n", style, size.cx, 0,
ok((size.cx == 0 && size.cy > 0),
"Style 0x%08x expect ideal cx %d == %d and ideal cy %d > %d\n", style, size.cx, 0,
size.cy, 0);
}
else
@ -1718,8 +2226,58 @@ static void test_bcm_get_ideal_size(void)
}
}
/* Command Link with note */
hwnd = CreateWindowA(WC_BUTTONA, "a", style, 0, 0, client_width, client_height, NULL, NULL, 0, NULL);
ok(hwnd != NULL, "Expected hwnd not NULL\n");
SendMessageA(hwnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp);
ret = SendMessageA(hwnd, BCM_SETNOTE, 0, (LPARAM)button_note_short);
ok(ret == TRUE, "Expected BCM_SETNOTE to return true\n");
size.cx = 13;
size.cy = 0;
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret == TRUE, "Expected BCM_GETIDEALSIZE message to return true\n");
ok(size.cx == 13 && size.cy > 0, "Expected ideal cx %d == %d and ideal cy %d > %d\n", size.cx, 13, size.cy, 0);
height = size.cy;
size.cx = 32767;
size.cy = 7;
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret == TRUE, "Expected BCM_GETIDEALSIZE message to return true\n");
ok(size.cx < 32767, "Expected ideal cx to have been adjusted\n");
ok(size.cx > image_width && size.cy == height, "Expected ideal cx %d > %d and ideal cy %d == %d\n", size.cx, image_width, size.cy, height);
/* Try longer note without word breaks, shouldn't extend height because no word splitting */
ret = SendMessageA(hwnd, BCM_SETNOTE, 0, (LPARAM)button_note_long);
ok(ret == TRUE, "Expected BCM_SETNOTE to return true\n");
k = size.cx;
size.cy = 0;
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret == TRUE, "Expected BCM_GETIDEALSIZE message to return true\n");
ok(size.cx == k && size.cy == height, "Expected ideal cx %d == %d and ideal cy %d == %d\n", size.cx, k, size.cy, height);
/* Now let it extend the width */
size.cx = 32767;
size.cy = 0;
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret == TRUE, "Expected BCM_GETIDEALSIZE message to return true\n");
ok(size.cx > k && size.cy == height, "Expected ideal cx %d > %d and ideal cy %d == %d\n", size.cx, k, size.cy, height);
/* Use a very long note with words and the same width, should extend the height due to word wrap */
ret = SendMessageA(hwnd, BCM_SETNOTE, 0, (LPARAM)button_note_wordy);
ok(ret == TRUE, "Expected BCM_SETNOTE to return true\n");
k = size.cx;
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret == TRUE, "Expected BCM_GETIDEALSIZE message to return true\n");
ok(size.cx <= k && size.cy > height, "Expected ideal cx %d <= %d and ideal cy %d > %d\n", size.cx, k, size.cy, height);
/* Now try the wordy note with a width smaller than the image itself, which prevents wrapping */
size.cx = 13;
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret == TRUE, "Expected BCM_GETIDEALSIZE message to return true\n");
ok(size.cx == 13 && size.cy == height, "Expected ideal cx %d == %d and ideal cy %d == %d\n", size.cx, 13, size.cy, height);
DestroyWindow(hwnd);
pImageList_Destroy(himl);
DestroyIcon(hicon);
DeleteObject(hbmp);
DeleteObject(hmask);
ReleaseDC(0, hdc);

View file

@ -1485,16 +1485,31 @@ static void test_edit_control_scroll(void)
DestroyWindow (hwEdit);
}
static BOOL is_cjk(HDC dc)
{
const DWORD FS_DBCS_MASK = FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB;
FONTSIGNATURE fs;
switch (GdiGetCodePage(dc)) {
case 932: case 936: case 949: case 950: case 1361:
return TRUE;
default:
return (GetTextCharsetInfo(dc, &fs, 0) != DEFAULT_CHARSET &&
(fs.fsCsb[0] & FS_DBCS_MASK));
}
}
static void test_margins_usefontinfo(UINT charset)
{
INT margins, threshold, expect, empty_expect, small_expect;
HWND hwnd;
HDC hdc;
TEXTMETRICW tm;
SIZE size;
BOOL cjk;
LOGFONTA lf;
HFONT hfont;
RECT rect;
INT margins, threshold, expect, empty_expect;
const UINT small_margins = MAKELONG(1, 5);
memset(&lf, 0, sizeof(lf));
lf.lfHeight = -11;
@ -1513,43 +1528,31 @@ static void test_margins_usefontinfo(UINT charset)
hdc = GetDC(hwnd);
hfont = SelectObject(hdc, hfont);
size.cx = GdiGetCharDimensions( hdc, NULL, &size.cy );
expect = MAKELONG(size.cx / 2, size.cx / 2);
small_expect = 0;
empty_expect = size.cx >= 28 ? small_expect : expect;
charset = GetTextCharset(hdc);
switch (charset)
{
case SHIFTJIS_CHARSET:
case HANGUL_CHARSET:
case GB2312_CHARSET:
case CHINESEBIG5_CHARSET:
cjk = TRUE;
break;
default:
cjk = FALSE;
size.cx = GdiGetCharDimensions( hdc, &tm, &size.cy );
if ((charset != tm.tmCharSet && charset != DEFAULT_CHARSET) ||
!(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) {
skip("%s for charset %d isn't available\n", lf.lfFaceName, charset);
hfont = SelectObject(hdc, hfont);
ReleaseDC(hwnd, hdc);
DestroyWindow(hwnd);
DeleteObject(hfont);
return;
}
expect = MAKELONG(size.cx / 2, size.cx / 2);
hfont = SelectObject(hdc, hfont);
ReleaseDC(hwnd, hdc);
margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
ok(margins == 0, "got %x\n", margins);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
if (!cjk)
ok(margins == expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins));
else
{
ok(HIWORD(margins) > 0 && LOWORD(margins) > 0, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins));
expect = empty_expect = small_expect = margins;
}
SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO));
expect = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
DestroyWindow(hwnd);
threshold = (size.cx / 2 + size.cx) * 2;
threshold = HIWORD(expect) + LOWORD(expect) + size.cx * 2;
empty_expect = threshold > 80 ? small_margins : expect;
/* Size below which non-cjk margins are zero */
/* Size below the threshold, margins remain unchanged */
hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, threshold - 1, 100, NULL, NULL, NULL, NULL);
ok(hwnd != NULL, "got %p\n", hwnd);
GetClientRect(hwnd, &rect);
@ -1559,11 +1562,13 @@ static void test_margins_usefontinfo(UINT charset)
ok(margins == 0, "got %x\n", margins);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins);
SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO));
margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
ok(margins == small_expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins));
ok(margins == small_margins, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins));
DestroyWindow(hwnd);
/* Size at which non-cjk margins become non-zero */
/* Size at the threshold, margins become non-zero */
hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, threshold, 100, NULL, NULL, NULL, NULL);
ok(hwnd != NULL, "got %p\n", hwnd);
GetClientRect(hwnd, &rect);
@ -1573,6 +1578,8 @@ static void test_margins_usefontinfo(UINT charset)
ok(margins == 0, "got %x\n", margins);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins);
SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO));
margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
ok(margins == expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins));
DestroyWindow(hwnd);
@ -1587,6 +1594,8 @@ static void test_margins_usefontinfo(UINT charset)
ok(margins == 0, "got %x\n", margins);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins);
SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO));
margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
ok(margins == empty_expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins));
DestroyWindow(hwnd);
@ -1594,6 +1603,151 @@ static void test_margins_usefontinfo(UINT charset)
DeleteObject(hfont);
}
static INT get_cjk_fontinfo_margin(INT width, INT side_bearing)
{
INT margin;
if (side_bearing < 0)
margin = min(-side_bearing, width/2);
else
margin = 0;
return margin;
}
static DWORD get_cjk_font_margins(HDC hdc)
{
ABC abc[256];
SHORT left, right;
UINT i;
if (!GetCharABCWidthsW(hdc, 0, 255, abc))
return 0;
left = right = 0;
for (i = 0; i < ARRAY_SIZE(abc); i++) {
if (-abc[i].abcA > right) right = -abc[i].abcA;
if (-abc[i].abcC > left) left = -abc[i].abcC;
}
return MAKELONG(left, right);
}
static void test_margins_default(const char* facename, UINT charset)
{
HWND hwnd;
HDC hdc;
TEXTMETRICW tm;
SIZE size;
BOOL cjk;
LOGFONTA lf;
HFONT hfont;
RECT rect;
INT margins, expect, font_expect;
const UINT small_margins = MAKELONG(1, 5);
const WCHAR EditW[] = {'E','d','i','t',0}, strW[] = {'W',0};
struct char_width_info {
INT lsb, rsb, unknown;
} info;
HMODULE hgdi32;
BOOL (WINAPI *pGetCharWidthInfo)(HDC, struct char_width_info *);
hgdi32 = GetModuleHandleA("gdi32.dll");
pGetCharWidthInfo = (void *)GetProcAddress(hgdi32, "GetCharWidthInfo");
memset(&lf, 0, sizeof(lf));
lf.lfHeight = -11;
lf.lfWeight = FW_NORMAL;
lf.lfCharSet = charset;
strcpy(lf.lfFaceName, facename);
hfont = CreateFontIndirectA(&lf);
ok(hfont != NULL, "got %p\n", hfont);
/* Unicode version */
hwnd = CreateWindowExW(0, EditW, strW, WS_POPUP, 0, 0, 5000, 1000, NULL, NULL, NULL, NULL);
ok(hwnd != NULL, "got %p\n", hwnd);
GetClientRect(hwnd, &rect);
ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect));
hdc = GetDC(hwnd);
hfont = SelectObject(hdc, hfont);
size.cx = GdiGetCharDimensions( hdc, &tm, &size.cy );
if ((charset != tm.tmCharSet && charset != DEFAULT_CHARSET) ||
!(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) {
skip("%s for charset %d isn't available\n", lf.lfFaceName, charset);
hfont = SelectObject(hdc, hfont);
ReleaseDC(hwnd, hdc);
DestroyWindow(hwnd);
DeleteObject(hfont);
return;
}
cjk = is_cjk(hdc);
if (cjk && pGetCharWidthInfo && pGetCharWidthInfo(hdc, &info)) {
short left, right;
left = get_cjk_fontinfo_margin(size.cx, info.lsb);
right = get_cjk_fontinfo_margin(size.cx, info.rsb);
expect = MAKELONG(left, right);
font_expect = get_cjk_font_margins(hdc);
if (!font_expect)
/* In this case, margins aren't updated */
font_expect = small_margins;
}
else
font_expect = expect = MAKELONG(size.cx / 2, size.cx / 2);
hfont = SelectObject(hdc, hfont);
ReleaseDC(hwnd, hdc);
margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
ok(margins == 0, "got %x\n", margins);
SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
ok(margins == font_expect, "%s:%d: got %d, %d\n", facename, charset, HIWORD(margins), LOWORD(margins));
SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins);
SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO));
margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
ok(margins == expect, "%s:%d: expected %d, %d, got %d, %d\n", facename, charset, HIWORD(expect), LOWORD(expect), HIWORD(margins), LOWORD(margins));
DestroyWindow(hwnd);
/* ANSI version */
hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, 5000, 1000, NULL, NULL, NULL, NULL);
ok(hwnd != NULL, "got %p\n", hwnd);
GetClientRect(hwnd, &rect);
ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect));
margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
ok(margins == 0, "got %x\n", margins);
SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
ok(margins == font_expect, "%s:%d: got %d, %d\n", facename, charset, HIWORD(margins), LOWORD(margins));
SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins);
SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO));
margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0);
ok(margins == expect, "%s:%d: expected %d, %d, got %d, %d\n", facename, charset, HIWORD(expect), LOWORD(expect), HIWORD(margins), LOWORD(margins));
DestroyWindow(hwnd);
DeleteObject(hfont);
}
static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
{
return 0;
}
static BOOL is_font_installed(const char*name)
{
HDC hdc = GetDC(NULL);
BOOL ret = FALSE;
if (!EnumFontFamiliesA(hdc, name, find_font_proc, 0))
ret = TRUE;
ReleaseDC(NULL, hdc);
return ret;
}
static void test_margins(void)
{
DWORD old_margins, new_margins;
@ -1668,27 +1822,45 @@ static void test_margins(void)
but not by < Win 8 and Win 10. */
test_margins_usefontinfo(DEFAULT_CHARSET);
}
static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
{
return 0;
test_margins_default("Tahoma", ANSI_CHARSET);
test_margins_default("Tahoma", EASTEUROPE_CHARSET);
test_margins_default("Tahoma", HANGUL_CHARSET);
test_margins_default("Tahoma", CHINESEBIG5_CHARSET);
if (is_font_installed("MS PGothic")) {
test_margins_default("MS PGothic", SHIFTJIS_CHARSET);
test_margins_default("MS PGothic", GREEK_CHARSET);
}
else
skip("MS PGothic is not available, skipping some margin tests\n");
if (is_font_installed("Ume P Gothic")) {
test_margins_default("Ume P Gothic", SHIFTJIS_CHARSET);
test_margins_default("Ume P Gothic", GREEK_CHARSET);
}
else
skip("Ume P Gothic is not available, skipping some margin tests\n");
if (is_font_installed("SimSun")) {
test_margins_default("SimSun", GB2312_CHARSET);
test_margins_default("SimSun", ANSI_CHARSET);
}
else
skip("SimSun is not available, skipping some margin tests\n");
}
static void test_margins_font_change(void)
{
DWORD margins, font_margins, ret;
DWORD margins, font_margins;
HFONT hfont, hfont2;
HWND hwEdit;
LOGFONTA lf;
HDC hdc;
hdc = GetDC(0);
ret = EnumFontFamiliesA(hdc, "Arial", find_font_proc, 0);
ReleaseDC(0, hdc);
if (ret)
if (!is_font_installed("Arial"))
{
trace("Arial not found - skipping font change margin tests\n");
skip("Arial not found - skipping font change margin tests\n");
return;
}
@ -1699,7 +1871,7 @@ static void test_margins_font_change(void)
memset(&lf, 0, sizeof(lf));
strcpy(lf.lfFaceName, "Arial");
lf.lfHeight = 16;
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfCharSet = GREEK_CHARSET; /* to avoid associated charset feature */
hfont = CreateFontIndirectA(&lf);
lf.lfHeight = 30;
hfont2 = CreateFontIndirectA(&lf);
@ -3143,6 +3315,9 @@ static void test_change_focus(void)
HWND hwnd, parent_wnd;
WNDPROC oldproc;
MSG msg;
POINT orig_pos;
GetCursorPos(&orig_pos);
parent_wnd = CreateWindowA("ParentWnd", "", WS_OVERLAPPEDWINDOW,
0, 0, 200, 200, NULL, NULL, GetModuleHandleA(NULL), NULL);
@ -3157,6 +3332,8 @@ static void test_change_focus(void)
oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)edit_subclass_proc);
SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
SetCursorPos(400, 400);
SetFocus(parent_wnd);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
SetFocus(hwnd);
@ -3168,6 +3345,8 @@ static void test_change_focus(void)
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
ok_sequence(sequences, COMBINED_SEQ_INDEX, killfocus_combined_seq, "Kill focus", TRUE);
SetCursorPos(orig_pos.x, orig_pos.y);
DestroyWindow(hwnd);
}

View file

@ -1563,7 +1563,6 @@ cleanup:
if(hbmDst)
DeleteObject(hbmDst);
if(hdcDst)
DeleteDC(hdcDst);
if(hbmMask)
@ -2181,7 +2180,7 @@ static void test_color_table(UINT ilc)
rgb[2].rgbBlue = 0xff;
check_color_table("remove all, add 8", hdc, himl, ilc, rgb, default_table);
/* remove all, add 4. Color table remains the same since it's inplicitly
/* remove all, add 4. Color table remains the same since it's implicitly
been set by the previous _Add */
ret = pImageList_Remove(himl, -1);
ok(ret, "got %d\n", ret);

View file

@ -784,6 +784,135 @@ static void test_listbox_height(void)
DestroyWindow( hList );
}
static void test_changing_selection_styles(void)
{
static const DWORD styles[] =
{
0,
LBS_NODATA | LBS_OWNERDRAWFIXED
};
static const DWORD selstyles[] =
{
0,
LBS_MULTIPLESEL,
LBS_EXTENDEDSEL,
LBS_MULTIPLESEL | LBS_EXTENDEDSEL
};
static const LONG selexpect_single[] = { 0, 0, 1 };
static const LONG selexpect_single2[] = { 1, 0, 0 };
static const LONG selexpect_multi[] = { 1, 0, 1 };
static const LONG selexpect_multi2[] = { 1, 1, 0 };
HWND parent, listbox;
DWORD style;
LONG ret;
UINT i, j, k;
parent = create_parent();
ok(parent != NULL, "Failed to create parent window.\n");
for (i = 0; i < ARRAY_SIZE(styles); i++)
{
/* Test if changing selection styles affects selection storage */
for (j = 0; j < ARRAY_SIZE(selstyles); j++)
{
LONG setcursel_expect, selitemrange_expect, getselcount_expect;
const LONG *selexpect;
listbox = CreateWindowA(WC_LISTBOXA, "TestList", styles[i] | selstyles[j] | WS_CHILD | WS_VISIBLE,
0, 0, 100, 100, parent, (HMENU)ID_LISTBOX, NULL, 0);
ok(listbox != NULL, "%u: Failed to create ListBox window.\n", j);
if (selstyles[j] & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL))
{
setcursel_expect = LB_ERR;
selitemrange_expect = LB_OKAY;
getselcount_expect = 2;
selexpect = selexpect_multi;
}
else
{
setcursel_expect = 2;
selitemrange_expect = LB_ERR;
getselcount_expect = LB_ERR;
selexpect = selexpect_single;
}
for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++)
{
ret = SendMessageA(listbox, LB_INSERTSTRING, -1, (LPARAM)"x");
ok(ret == k, "%u: Unexpected return value %d, expected %d.\n", j, ret, k);
}
ret = SendMessageA(listbox, LB_GETCOUNT, 0, 0);
ok(ret == ARRAY_SIZE(selexpect_multi), "%u: Unexpected count %d.\n", j, ret);
/* Select items with different methods */
ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
ok(ret == setcursel_expect, "%u: Unexpected return value %d.\n", j, ret);
ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 0));
ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret);
ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 2));
ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret);
/* Verify that the proper items are selected */
for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++)
{
ret = SendMessageA(listbox, LB_GETSEL, k, 0);
ok(ret == selexpect[k], "%u: Unexpected selection state %d, expected %d.\n",
j, ret, selexpect[k]);
}
/* Now change the selection style */
style = GetWindowLongA(listbox, GWL_STYLE);
ok((style & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == selstyles[j],
"%u: unexpected window styles %#x.\n", j, style);
if (selstyles[j] & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL))
style &= ~selstyles[j];
else
style |= LBS_MULTIPLESEL | LBS_EXTENDEDSEL;
SetWindowLongA(listbox, GWL_STYLE, style);
style = GetWindowLongA(listbox, GWL_STYLE);
ok(!(style & selstyles[j]), "%u: unexpected window styles %#x.\n", j, style);
/* Verify that the same items are selected */
ret = SendMessageA(listbox, LB_GETSELCOUNT, 0, 0);
ok(ret == getselcount_expect, "%u: expected %d from LB_GETSELCOUNT, got %d\n",
j, getselcount_expect, ret);
for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++)
{
ret = SendMessageA(listbox, LB_GETSEL, k, 0);
ok(ret == selexpect[k], "%u: Unexpected selection state %d, expected %d.\n",
j, ret, selexpect[k]);
}
/* Lastly see if we can still change the selection as before with old style */
if (setcursel_expect != LB_ERR) setcursel_expect = 0;
ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
ok(ret == setcursel_expect, "%u: Unexpected return value %d.\n", j, ret);
ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 1));
ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret);
ret = SendMessageA(listbox, LB_SELITEMRANGE, FALSE, MAKELPARAM(2, 2));
ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret);
/* And verify the selections */
selexpect = (selstyles[j] & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) ? selexpect_multi2 : selexpect_single2;
ret = SendMessageA(listbox, LB_GETSELCOUNT, 0, 0);
ok(ret == getselcount_expect, "%u: expected %d from LB_GETSELCOUNT, got %d\n",
j, getselcount_expect, ret);
for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++)
{
ret = SendMessageA(listbox, LB_GETSEL, k, 0);
ok(ret == selexpect[k], "%u: Unexpected selection state %d, expected %d.\n",
j, ret, selexpect[k]);
}
DestroyWindow(listbox);
}
}
DestroyWindow(parent);
}
static void test_itemfrompoint(void)
{
/* WS_POPUP is required in order to have a more accurate size calculation (
@ -1812,7 +1941,7 @@ static void test_listbox_dlgdir(void)
strcpy(pathBuffer, "C:\\");
res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
ok(res, "DlgDirList failed to list C:\\ folders\n");
todo_wine ok(!strcmp(pathBuffer, "*"), "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
ok(!strcmp(pathBuffer, "*"), "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
strcpy(pathBuffer, "C:\\*");
res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
@ -1823,8 +1952,8 @@ static void test_listbox_dlgdir(void)
SetLastError(0xdeadbeef);
strcpy(pathBuffer, "C:\\INVALID$$DIR");
res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
todo_wine ok(!res, "DlgDirList should have failed with 0 but %d was returned\n", res);
todo_wine ok(GetLastError() == ERROR_NO_WILDCARD_CHARACTERS,
ok(!res, "DlgDirList should have failed with 0 but %d was returned\n", res);
ok(GetLastError() == ERROR_NO_WILDCARD_CHARACTERS,
"GetLastError should return 0x589, got 0x%X\n",GetLastError());
DestroyWindow(hWnd);
@ -1867,6 +1996,11 @@ static void test_set_count( void )
GetUpdateRect( listbox, &r, TRUE );
ok( !IsRectEmpty( &r ), "got empty rect\n");
ret = SendMessageA( listbox, LB_SETCOUNT, -5, 0 );
ok( ret == 0, "got %d\n", ret );
ret = SendMessageA( listbox, LB_GETCOUNT, 0, 0 );
ok( ret == -5, "got %d\n", ret );
DestroyWindow( listbox );
for (i = 0; i < ARRAY_SIZE(styles); ++i)
@ -1906,6 +2040,69 @@ static void test_GetListBoxInfo(void)
DestroyWindow(parent);
}
static void test_init_storage( void )
{
static const DWORD styles[] =
{
LBS_HASSTRINGS,
LBS_NODATA | LBS_OWNERDRAWFIXED,
};
HWND parent, listbox;
LONG ret, items_size;
int i, j;
parent = create_parent();
for (i = 0; i < ARRAY_SIZE(styles); i++)
{
listbox = CreateWindowA(WC_LISTBOXA, "TestList", styles[i] | WS_CHILD,
0, 0, 100, 100, parent, (HMENU)ID_LISTBOX, NULL, 0);
items_size = SendMessageA(listbox, LB_INITSTORAGE, 100, 0);
ok(items_size >= 100, "expected at least 100, got %d\n", items_size);
ret = SendMessageA(listbox, LB_INITSTORAGE, 0, 0);
ok(ret == items_size, "expected %d, got %d\n", items_size, ret);
/* it doesn't grow since the space was already reserved */
ret = SendMessageA(listbox, LB_INITSTORAGE, items_size, 0);
ok(ret == items_size, "expected %d, got %d\n", items_size, ret);
/* it doesn't shrink the reserved space */
ret = SendMessageA(listbox, LB_INITSTORAGE, 42, 0);
ok(ret == items_size, "expected %d, got %d\n", items_size, ret);
/* now populate almost all of it so it's not reserved anymore */
if (styles[i] & LBS_NODATA)
{
ret = SendMessageA(listbox, LB_SETCOUNT, items_size - 1, 0);
ok(ret == 0, "unexpected return value %d\n", ret);
}
else
{
for (j = 0; j < items_size - 1; j++)
{
ret = SendMessageA(listbox, LB_INSERTSTRING, -1, (LPARAM)"");
ok(ret == j, "expected %d, got %d\n", j, ret);
}
}
/* we still have one more reserved slot, so it doesn't grow yet */
ret = SendMessageA(listbox, LB_INITSTORAGE, 1, 0);
ok(ret == items_size, "expected %d, got %d\n", items_size, ret);
/* fill the slot and check again, it should grow this time */
ret = SendMessageA(listbox, LB_INSERTSTRING, -1, (LPARAM)"");
ok(ret == items_size - 1, "expected %d, got %d\n", items_size - 1, ret);
ret = SendMessageA(listbox, LB_INITSTORAGE, 0, 0);
ok(ret == items_size, "expected %d, got %d\n", items_size, ret);
ret = SendMessageA(listbox, LB_INITSTORAGE, 1, 0);
ok(ret > items_size, "expected it to grow past %d, got %d\n", items_size, ret);
DestroyWindow(listbox);
}
DestroyWindow(parent);
}
static void test_missing_lbuttonup(void)
{
HWND listbox, parent, capture;
@ -2420,11 +2617,13 @@ START_TEST(listbox)
test_LB_SELITEMRANGE();
test_LB_SETCURSEL();
test_listbox_height();
test_changing_selection_styles();
test_itemfrompoint();
test_listbox_item_data();
test_listbox_LB_DIR();
test_listbox_dlgdir();
test_set_count();
test_init_storage();
test_GetListBoxInfo();
test_missing_lbuttonup();
test_extents();

View file

@ -6475,6 +6475,86 @@ static void test_LVM_GETCOUNTPERPAGE(void)
ok(ret, "Failed to unregister test class.\n");
}
static void test_item_state_change(void)
{
static const DWORD styles[] = { LVS_ICON, LVS_LIST, LVS_REPORT, LVS_SMALLICON };
LVITEMA item;
HWND hwnd;
DWORD res;
int i;
for (i = 0; i < ARRAY_SIZE(styles); i++)
{
hwnd = create_listview_control(styles[i]);
insert_item(hwnd, 0);
/* LVM_SETITEMSTATE with mask */
memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
memset(&item, 0, sizeof(item));
item.mask = LVIF_STATE;
item.stateMask = LVIS_SELECTED;
item.state = LVIS_SELECTED;
res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
ok(res, "Failed to set item state.\n");
ok(g_nmlistview.iItem == item.iItem, "Unexpected item %d.\n", g_nmlistview.iItem);
ok(g_nmlistview.iSubItem == item.iSubItem, "Unexpected subitem %d.\n", g_nmlistview.iSubItem);
ok(g_nmlistview.lParam == item.lParam, "Unexpected lParam.\n");
ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
/* LVM_SETITEMSTATE 0 mask */
memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
memset(&item, 0, sizeof(item));
item.stateMask = LVIS_SELECTED;
item.state = 0;
res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
ok(res, "Failed to set item state.\n");
ok(g_nmlistview.iItem == item.iItem, "Unexpected item %d.\n", g_nmlistview.iItem);
ok(g_nmlistview.iSubItem == item.iSubItem, "Unexpected subitem %d.\n", g_nmlistview.iSubItem);
ok(g_nmlistview.lParam == item.lParam, "Unexpected lParam.\n");
ok(g_nmlistview.uNewState == 0, "Unexpected new state %#x.\n", g_nmlistview.uNewState);
ok(g_nmlistview.uOldState == LVIS_SELECTED, "Unexpected old state %#x.\n", g_nmlistview.uOldState);
ok(g_nmlistview.uChanged == LVIF_STATE, "Unexpected change mask %#x.\n", g_nmlistview.uChanged);
/* LVM_SETITEM changes state */
memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
memset(&item, 0, sizeof(item));
item.stateMask = LVIS_SELECTED;
item.state = LVIS_SELECTED;
item.mask = LVIF_STATE;
res = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
ok(res, "Failed to set item.\n");
ok(g_nmlistview.iItem == item.iItem, "Unexpected item %d.\n", g_nmlistview.iItem);
ok(g_nmlistview.iSubItem == item.iSubItem, "Unexpected subitem %d.\n", g_nmlistview.iSubItem);
ok(g_nmlistview.lParam == item.lParam, "Unexpected lParam.\n");
ok(g_nmlistview.uNewState == LVIS_SELECTED, "Unexpected new state %#x.\n", g_nmlistview.uNewState);
ok(g_nmlistview.uOldState == 0, "Unexpected old state %#x.\n", g_nmlistview.uOldState);
ok(g_nmlistview.uChanged == LVIF_STATE, "Unexpected change mask %#x.\n", g_nmlistview.uChanged);
/* LVM_SETITEM no state changes */
memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
memset(&item, 0, sizeof(item));
item.lParam = 11;
item.mask = LVIF_PARAM;
res = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
ok(res, "Failed to set item.\n");
ok(g_nmlistview.iItem == item.iItem, "Unexpected item %d.\n", g_nmlistview.iItem);
ok(g_nmlistview.iSubItem == item.iSubItem, "Unexpected subitem %d.\n", g_nmlistview.iSubItem);
ok(g_nmlistview.lParam == item.lParam, "Unexpected lParam.\n");
ok(g_nmlistview.uNewState == 0, "Unexpected new state %#x.\n", g_nmlistview.uNewState);
ok(g_nmlistview.uOldState == 0, "Unexpected old state %#x.\n", g_nmlistview.uOldState);
ok(g_nmlistview.uChanged == LVIF_PARAM, "Unexpected change mask %#x.\n", g_nmlistview.uChanged);
DestroyWindow(hwnd);
}
}
START_TEST(listview)
{
ULONG_PTR ctx_cookie;
@ -6538,6 +6618,7 @@ START_TEST(listview)
test_LVSCW_AUTOSIZE();
test_LVN_ENDLABELEDIT();
test_LVM_GETCOUNTPERPAGE();
test_item_state_change();
if (!load_v6_module(&ctx_cookie, &hCtx))
{
@ -6582,6 +6663,7 @@ START_TEST(listview)
test_LVSCW_AUTOSIZE();
test_LVN_ENDLABELEDIT();
test_LVM_GETCOUNTPERPAGE();
test_item_state_change();
unload_v6_module(ctx_cookie, hCtx);

View file

@ -564,9 +564,11 @@ static void test_wm_notifyformat(void)
static const INT formats[] = {NFR_UNICODE, NFR_ANSI};
HWND parent, pager, child;
LRESULT ret;
BOOL bret;
INT i;
ok(register_notifyformat_class(), "Register test class failed, error 0x%08x\n", GetLastError());
bret = register_notifyformat_class();
ok(bret, "Register test class failed, error 0x%08x\n", GetLastError());
for (i = 0; i < ARRAY_SIZE(formats); i++)
{
@ -1280,9 +1282,11 @@ static void test_wm_notify(void)
{&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax,
TVN_SELCHANGEDW, TVN_SELCHANGEDA, CONVERT_SEND, TVITEM_OLD_HANDLER}
};
BOOL bret;
INT i;
ok(register_test_notify_class(), "Register test class failed, error 0x%08x\n", GetLastError());
bret = register_test_notify_class();
ok(bret, "Register test class failed, error 0x%08x\n", GetLastError());
parent = CreateWindowA(class, "parent", WS_OVERLAPPED, 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), 0);
ok(parent != NULL, "CreateWindow failed\n");

View file

@ -254,6 +254,13 @@ static void test_PBM_STEPIT(void)
{ 3, 15, 5 },
{ 3, 15, -5 },
{ 3, 15, 50 },
{ -15, 15, 5 },
{ -3, -2, -5 },
{ 0, 0, 1 },
{ 5, 5, 1 },
{ 0, 0, -1 },
{ 5, 5, -1 },
{ 10, 5, 2 },
};
HWND progress;
int i, j;
@ -261,6 +268,7 @@ static void test_PBM_STEPIT(void)
for (i = 0; i < ARRAY_SIZE(stepit_tests); i++)
{
struct stepit_test *test = &stepit_tests[i];
PBRANGE range;
LRESULT ret;
progress = create_progress(0);
@ -268,6 +276,9 @@ static void test_PBM_STEPIT(void)
ret = SendMessageA(progress, PBM_SETRANGE32, test->min, test->max);
ok(ret != 0, "Unexpected return value.\n");
SendMessageA(progress, PBM_GETRANGE, 0, (LPARAM)&range);
ok(range.iLow == test->min && range.iHigh == test->max, "Unexpected range.\n");
SendMessageA(progress, PBM_SETPOS, test->min, 0);
SendMessageA(progress, PBM_SETSTEP, test->step, 0);
@ -277,15 +288,20 @@ static void test_PBM_STEPIT(void)
int current;
pos += test->step;
if (test->min != test->max)
{
if (pos > test->max)
pos = (pos - test->min) % (test->max - test->min) + test->min;
if (pos < test->min)
pos = (pos - test->min) % (test->max - test->min) + test->max;
}
else
pos = test->min;
SendMessageA(progress, PBM_STEPIT, 0, 0);
current = SendMessageA(progress, PBM_GETPOS, 0, 0);
ok(current == pos, "Unexpected position %d, expected %d.\n", current, pos);
ok(current == pos, "%u: unexpected position %d, expected %d.\n", i, current, pos);
}
DestroyWindow(progress);

View file

@ -273,6 +273,9 @@ static void test_subclass(void)
ret = pSetWindowSubclass(hwnd, NULL, 1, 0);
ok(ret == FALSE, "Expected FALSE\n");
pRemoveWindowSubclass(hwnd, wnd_proc_sub, 2);
pRemoveWindowSubclass(hwnd, wnd_proc_sub, 5);
DestroyWindow(hwnd);
}

View file

@ -931,7 +931,7 @@ static void test_selection(void)
static void test_thumb_length(void)
{
HWND hWndTrackbar;
int r;
int r, r2;
hWndTrackbar = create_trackbar(defaultstyle, hWndParent);
ok(hWndTrackbar != NULL, "Expected non NULL value\n");
@ -963,6 +963,22 @@ static void test_thumb_length(void)
ok_sequence(sequences, PARENT_SEQ_INDEX, parent_thumb_length_test_seq, "parent thumb length test sequence", TRUE);
DestroyWindow(hWndTrackbar);
/* Fixed thumb length does not depend on window size. */
hWndTrackbar = CreateWindowA(TRACKBAR_CLASSA, "Trackbar Control", WS_VISIBLE | TBS_ENABLESELRANGE
| TBS_FIXEDLENGTH, 0, 0, 0, 0, hWndParent, NULL, GetModuleHandleA(NULL), NULL);
r = SendMessageA(hWndTrackbar, TBM_GETTHUMBLENGTH, 0, 0);
DestroyWindow(hWndTrackbar);
hWndTrackbar = CreateWindowA(TRACKBAR_CLASSA, "Trackbar Control", WS_VISIBLE | TBS_ENABLESELRANGE
| TBS_FIXEDLENGTH, 0, 0, 200, 200, hWndParent, NULL, GetModuleHandleA(NULL), NULL);
r2 = SendMessageA(hWndTrackbar, TBM_GETTHUMBLENGTH, 0, 0);
ok(r2 == r, "Unexpected thumb length %d.\n", r);
DestroyWindow(hWndTrackbar);
}
static void test_tic_settings(void)

View file

@ -1364,7 +1364,7 @@ static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam,
visibleItem = (HTREEITEM)SendMessageA(pHdr->hwndFrom, TVM_GETNEXTITEM,
TVGN_NEXTVISIBLE, (LPARAM)visibleItem);
*(HTREEITEM*)&rect = visibleItem;
ok(visibleItem != NULL, "There must be a visible item after the first visisble item.\n");
ok(visibleItem != NULL, "There must be a visible item after the first one.\n");
ok(SendMessageA(pHdr->hwndFrom, TVM_GETITEMRECT, TRUE, (LPARAM)&rect),
"Failed to get rect for second visible item.\n");
}

View file

@ -28,7 +28,6 @@
* - check UDM_SETBUDDY message
* - check UDM_GETBUDDY message
* - up-down control and buddy control must have the same parent
* - up-down control notifies its parent window when its position changes with UDN_DELTAPOS + WM_VSCROLL or WM_HSCROLL
* - check UDS_ALIGN[LEFT,RIGHT]...check that width of buddy window is decreased
* - check that UDS_SETBUDDYINT sets the caption of the buddy window when it is changed
* - check that the thousands operator is set for large numbers
@ -165,6 +164,32 @@ static const struct message test_updown_pos_nochange_seq[] = {
{ 0 }
};
static const struct message test_updown_pos_notifications_seq[] = {
{ WM_CTLCOLOREDIT, sent|optional },
{ WM_COMMAND, sent|wparam, MAKELONG(0, EN_SETFOCUS) },
{ WM_NOTIFY, sent|id, 0, 0, UDN_DELTAPOS },
{ WM_COMMAND, sent|wparam, MAKELONG(0, EN_UPDATE) },
{ WM_COMMAND, sent|wparam, MAKELONG(0, EN_CHANGE) },
{ WM_VSCROLL, sent|wparam, MAKELONG(SB_THUMBPOSITION, 51) },
{ WM_CTLCOLOREDIT, sent|optional },
{ WM_VSCROLL, sent|wparam, MAKELONG(SB_ENDSCROLL, 51) },
/* no WM_NOTIFY(NM_RELEASEDCAPTURE) message */
{ 0 }
};
static const struct message test_updown_pos_notifications_horz_seq[] = {
{ WM_CTLCOLOREDIT, sent|optional },
{ WM_COMMAND, sent|wparam, MAKELONG(0, EN_SETFOCUS) },
{ WM_NOTIFY, sent|id, 0, 0, UDN_DELTAPOS },
{ WM_COMMAND, sent|wparam, MAKELONG(0, EN_UPDATE) },
{ WM_COMMAND, sent|wparam, MAKELONG(0, EN_CHANGE) },
{ WM_HSCROLL, sent|wparam, MAKELONG(SB_THUMBPOSITION, 51) },
{ WM_CTLCOLOREDIT, sent|optional },
{ WM_HSCROLL, sent|wparam, MAKELONG(SB_ENDSCROLL, 51) },
/* no WM_NOTIFY(NM_RELEASEDCAPTURE) message */
{ 0 }
};
static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static LONG defwndproc_counter = 0;
@ -186,6 +211,8 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP
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);
}
@ -900,6 +927,52 @@ static void test_CreateUpDownControl(void)
DestroyWindow(updown);
}
static void test_updown_pos_notifications(void)
{
HWND updown;
RECT rect;
UINT x, y;
int result;
/* test updown control notifications without UDS_HORZ style */
updown = create_updown_control(UDS_ALIGNRIGHT | UDS_SETBUDDYINT, g_edit);
SetFocus(updown);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
/* click on the up-arrow button */
GetClientRect(updown, &rect);
x = rect.left + (rect.right - rect.left) / 2;
y = rect.top + (rect.bottom - rect.top) / 4;
result = SendMessageA(updown, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y));
expect(result, 0);
result = SendMessageA(updown, WM_LBUTTONUP, 0, MAKELPARAM(x, y));
expect(result, 0);
ok_sequence(sequences, PARENT_SEQ_INDEX, test_updown_pos_notifications_seq,
"test updown to parent notify (vertical)", FALSE);
DestroyWindow(updown);
/* test updown control notifications with UDS_HORZ style */
updown = create_updown_control(UDS_ALIGNRIGHT | UDS_SETBUDDYINT | UDS_HORZ, g_edit);
SetFocus(updown);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
/* click on the right-arrow button */
GetClientRect(updown, &rect);
x = rect.left + (rect.right - rect.left) * 3 / 4;
y = rect.top + (rect.bottom - rect.top) / 2;
result = SendMessageA(updown, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y));
expect(result, 0);
result = SendMessageA(updown, WM_LBUTTONUP, 0, MAKELPARAM(x, y));
expect(result, 0);
ok_sequence(sequences, PARENT_SEQ_INDEX, test_updown_pos_notifications_horz_seq,
"test updown to parent notify (horizontal)", FALSE);
DestroyWindow(updown);
}
static void init_functions(void)
{
HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
@ -931,6 +1004,7 @@ START_TEST(updown)
test_updown_unicode();
test_UDS_SETBUDDYINT();
test_CreateUpDownControl();
test_updown_pos_notifications();
DestroyWindow(g_edit);
DestroyWindow(parent_wnd);