[PATCH] comctl32/taskdialog: Implement nDefaultButton and add tests
Fabian Maurer <[email protected]> Sat, 4 Nov 2017 16:22:10 +0100
| Newsgroups | gmane.comp.emulators.wine.patches |
|---|---|
| Message-ID | <[email protected]> |
Signed-off-by: Fabian Maurer <[email protected]> --- dlls/comctl32/taskdialog.c | 21 +++++-- dlls/comctl32/tests/taskdialog.c | 115 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 6 deletions(-) diff --git a/dlls/comctl32/taskdialog.c b/dlls/comctl32/taskdialog.c index 5c4af2ab03..4f80311a61 100644 --- a/dlls/comctl32/taskdialog.c +++ b/dlls/comctl32/taskdialog.c @@ -151,7 +151,7 @@ static void taskdialog_get_text_extent(const struct taskdialog_template_desc *de } static unsigned int taskdialog_add_control(struct taskdialog_template_desc *desc, WORD id, const WCHAR *class, - HINSTANCE hInstance, const WCHAR *text, short x, short y, short cx, short cy) + HINSTANCE hInstance, const WCHAR *text, DWORD style, short x, short y, short cx, short cy) { struct taskdialog_control *control = Alloc(sizeof(*control)); unsigned int size, class_size, text_size; @@ -178,7 +178,7 @@ static unsigned int taskdialog_add_control(struct taskdialog_template_desc *desc control->template = template = Alloc(size); control->template_size = size; - template->style = WS_VISIBLE; + template->style = WS_VISIBLE | style; template->dwExtendedStyle = 0; template->x = x; template->y = y; @@ -206,7 +206,7 @@ static unsigned int taskdialog_add_static_label(struct taskdialog_template_desc taskdialog_get_text_extent(desc, str, TRUE, &sz); desc->dialog_height += DIALOG_SPACING; - size = taskdialog_add_control(desc, id, WC_STATICW, desc->taskconfig->hInstance, str, DIALOG_SPACING, + size = taskdialog_add_control(desc, id, WC_STATICW, desc->taskconfig->hInstance, str, 0, DIALOG_SPACING, desc->dialog_height, sz.cx, sz.cy); desc->dialog_height += sz.cy + DIALOG_SPACING; return size; @@ -268,6 +268,7 @@ static unsigned int taskdialog_add_buttons(struct taskdialog_template_desc *desc unsigned int location_x, *line_widths, alignment = ~0u; const TASKDIALOGCONFIG *taskconfig = desc->taskconfig; struct taskdialog_button_desc *buttons; + int default_button; /* Allocate enough memory for the custom and the default buttons. Maximum 6 default buttons possible. */ buttons_size = 6; @@ -340,18 +341,26 @@ static unsigned int taskdialog_add_buttons(struct taskdialog_template_desc *desc alignment = new_alignment; } + /* Check if the default button is actually valid, if no default to the first created button */ + default_button = buttons[0].id; + for (i = 0; i < count; i++) + if (buttons[i].id == taskconfig->nDefaultButton) + default_button = taskconfig->nDefaultButton; + /* Now that we got them all positioned, create all buttons */ location_x = alignment; for (i = 0; i < count; i++) { + DWORD style = (buttons[i].id == default_button) ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON; + if (i > 0 && buttons[i].line != buttons[i - 1].line) /* New line */ { location_x = alignment; desc->dialog_height += DIALOG_BUTTON_HEIGHT + DIALOG_SPACING; } - size += taskdialog_add_control(desc, buttons[i].id, WC_BUTTONW, buttons[i].hinst, buttons[i].text, location_x, - desc->dialog_height, buttons[i].width, DIALOG_BUTTON_HEIGHT); + size += taskdialog_add_control(desc, buttons[i].id, WC_BUTTONW, buttons[i].hinst, buttons[i].text, style, + location_x, desc->dialog_height, buttons[i].width, DIALOG_BUTTON_HEIGHT); location_x += buttons[i].width + DIALOG_SPACING; } @@ -583,7 +592,7 @@ HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *taskconfig, int *butto Free(template); if (button) *button = ret; - if (radio_button) *radio_button = taskconfig->nDefaultButton; + if (radio_button) *radio_button = FALSE; if (verification_flag_checked) *verification_flag_checked = TRUE; return S_OK; diff --git a/dlls/comctl32/tests/taskdialog.c b/dlls/comctl32/tests/taskdialog.c index dfb6808c38..589ada548f 100644 --- a/dlls/comctl32/tests/taskdialog.c +++ b/dlls/comctl32/tests/taskdialog.c @@ -33,6 +33,11 @@ #define NUM_MSG_SEQUENCES 1 #define TASKDIALOG_SEQ_INDEX 0 +#define TEST_NUM_BUTTONS 20 /* Number of custom buttons to test with */ + +#define ID_START 20 /* Lower IDs might be used by the system */ +#define ID_START_BUTTON (ID_START + 0) + static HRESULT (WINAPI *pTaskDialogIndirect)(const TASKDIALOGCONFIG *, int *, int *, BOOL *); static HRESULT (WINAPI *pTaskDialog)(HWND, HINSTANCE, const WCHAR *, const WCHAR *, const WCHAR *, TASKDIALOG_COMMON_BUTTON_FLAGS, const WCHAR *, int *); @@ -66,6 +71,48 @@ static const struct message_info msg_return_press_ok[] = { 0 } }; +static const struct message_info msg_return_press_yes[] = +{ + { TDN_CREATED, 0, 0, S_OK, msg_send_return }, + { TDN_BUTTON_CLICKED, IDYES, 0, S_OK, NULL }, + { 0 } +}; + +static const struct message_info msg_return_press_no[] = +{ + { TDN_CREATED, 0, 0, S_OK, msg_send_return }, + { TDN_BUTTON_CLICKED, IDNO, 0, S_OK, NULL }, + { 0 } +}; + +static const struct message_info msg_return_press_cancel[] = +{ + { TDN_CREATED, 0, 0, S_OK, msg_send_return }, + { TDN_BUTTON_CLICKED, IDCANCEL, 0, S_OK, NULL }, + { 0 } +}; + +static const struct message_info msg_return_press_retry[] = +{ + { TDN_CREATED, 0, 0, S_OK, msg_send_return }, + { TDN_BUTTON_CLICKED, IDRETRY, 0, S_OK, NULL }, + { 0 } +}; + +static const struct message_info msg_return_press_custom1[] = +{ + { TDN_CREATED, 0, 0, S_OK, msg_send_return }, + { TDN_BUTTON_CLICKED, ID_START_BUTTON, 0, S_OK, NULL }, + { 0 } +}; + +static const struct message_info msg_return_press_custom4[] = +{ + { TDN_CREATED, 0, 0, S_OK, msg_send_return }, + { TDN_BUTTON_CLICKED, ID_START_BUTTON + 3, 0, S_OK, NULL }, + { 0 } +}; + static void init_test_message(UINT message, WPARAM wParam, LPARAM lParam, struct message *msg) { msg->message = WM_TD_CALLBACK; @@ -138,6 +185,24 @@ static HRESULT CALLBACK taskdialog_callback_proc(HWND hwnd, UINT notification, return current_message_info[msg_pos].callback_retval; } +static TASKDIALOG_BUTTON* buttons_make(void) +{ + static const WCHAR str_format[] = {'%','0','2','d',0}; + static TASKDIALOG_BUTTON buttons[TEST_NUM_BUTTONS]; + static WCHAR titles[TEST_NUM_BUTTONS * 3]; /* Each button has two digits as title, plus null-terminator */ + int i; + + for (i = 0; i < TEST_NUM_BUTTONS; i++) + { + WCHAR *text = &titles[i * 3]; + wsprintfW(text, str_format, i); + + buttons[i].pszButtonText = text; + buttons[i].nButtonID = ID_START_BUTTON + i; + } + return buttons; +} + static void test_invalid_parameters(void) { TASKDIALOGCONFIG info = { 0 }; @@ -170,6 +235,55 @@ static void test_callback(void) run_test(&info, IDOK, 0, msg_return_press_ok, "Press VK_RETURN."); } +static void test_buttons(void) +{ + TASKDIALOG_BUTTON *custom_buttons; + TASKDIALOGCONFIG info = {0}; + + info.cbSize = sizeof(TASKDIALOGCONFIG); + info.pfCallback = taskdialog_callback_proc; + info.lpCallbackData = test_ref_data; + + custom_buttons = buttons_make(); + + /* Test nDefaultButton */ + + /* Test common buttons with invalid default ID */ + info.nDefaultButton = 0; /* Should default to first created button */ + info.dwCommonButtons = TDCBF_OK_BUTTON | TDCBF_YES_BUTTON | TDCBF_NO_BUTTON + | TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON; + run_test(&info, IDOK, 0, msg_return_press_ok, "default button: unset default"); + info.dwCommonButtons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON + | TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON; + run_test(&info, IDYES, 0, msg_return_press_yes, "default button: unset default"); + info.dwCommonButtons = TDCBF_NO_BUTTON | TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON; + run_test(&info, IDNO, 0, msg_return_press_no, "default button: unset default"); + info.dwCommonButtons = TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON; + run_test(&info, IDRETRY, 0, msg_return_press_retry, "default button: unset default"); + info.dwCommonButtons = TDCBF_CANCEL_BUTTON | TDCBF_CLOSE_BUTTON; + run_test(&info, IDCANCEL, 0, msg_return_press_cancel, "default button: unset default"); + + /* Test with all common and custom buttons and invalid default ID */ + info.nDefaultButton = 0xff; /* Random ID, should also default to first created button */ + info.cButtons = 10; + info.pButtons = custom_buttons; + run_test(&info, ID_START_BUTTON, 0, msg_return_press_custom1, "default button: invalid default, with common buttons"); + + /* Test with only custom buttons and invalid default ID */ + info.dwCommonButtons = 0; + run_test(&info, ID_START_BUTTON, 0, msg_return_press_custom1, "default button: invalid default, no common buttons"); + + /* Test with common and custom buttons and valid default ID */ + info.dwCommonButtons = TDCBF_OK_BUTTON | TDCBF_YES_BUTTON | TDCBF_NO_BUTTON + | TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON; + info.nDefaultButton = IDRETRY; + run_test(&info, IDRETRY, 0, msg_return_press_retry, "default button: valid default - 1"); + + /* Test with common and custom buttons and valid default ID */ + info.nDefaultButton = ID_START_BUTTON + 3; + run_test(&info, ID_START_BUTTON + 3, 0, msg_return_press_custom4, "default button: valid default - 2"); +} + START_TEST(taskdialog) { ULONG_PTR ctx_cookie; @@ -205,6 +319,7 @@ START_TEST(taskdialog) test_invalid_parameters(); test_callback(); + test_buttons(); unload_v6_module(ctx_cookie, hCtx); } -- 2.15.0