From: Fabian Maurer Subject: [18/18] comctl32: TaskDialog - Add ability to cancel dialog Message-Id: <20170224200412.12968-18-dark.shadow4@web.de> Date: Fri, 24 Feb 2017 21:04:12 +0100 In-Reply-To: <20170224200412.12968-1-dark.shadow4@web.de> References: <20170224200412.12968-1-dark.shadow4@web.de> Signed-off-by: Fabian Maurer --- dlls/comctl32/taskdialog.c | 28 ++++++++++++-- dlls/comctl32/tests/taskdialog.c | 81 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 4 deletions(-) diff --git a/dlls/comctl32/taskdialog.c b/dlls/comctl32/taskdialog.c index 829102a07d..6057468793 100644 --- a/dlls/comctl32/taskdialog.c +++ b/dlls/comctl32/taskdialog.c @@ -76,6 +76,7 @@ typedef struct HFONT font_default; HFONT font_main; HWND hwnd; + BOOL has_cancel; }taskdialog_info; struct list taskdialogs = LIST_INIT(taskdialogs); @@ -259,6 +260,10 @@ static void taskdialog_info_init(taskdialog_info **taskdialog, const TASKDIALOGC dialog->font_main = CreateFontW (19, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, 0, 0, CLEARTYPE_QUALITY, FF_DONTCARE, font_name); + dialog->has_cancel = (pTaskConfig->dwFlags & TDF_ALLOW_DIALOG_CANCELLATION) + || (pTaskConfig->dwFlags & TDF_CAN_BE_MINIMIZED) + || (pTaskConfig->dwCommonButtons & TDCBF_CANCEL_BUTTON); + *taskdialog = dialog; } @@ -316,12 +321,15 @@ static HRESULT callback(taskdialog_info *dialog, UINT uNotification, WPARAM wPar static void click_button(HWND hwndDlg, taskdialog_info *dialog, WORD command_id) { - HRESULT ret_callback = callback(dialog, TDN_BUTTON_CLICKED, command_id, 0); + HRESULT ret_callback; + + if(command_id == IDCANCEL && !dialog->has_cancel) + return TRUE; + + ret_callback = callback(dialog, TDN_BUTTON_CLICKED, command_id, 0); if(ret_callback == S_OK) { EndDialog(hwndDlg, command_id); - - callback(dialog, TDN_DESTROYED, 0, 0); } } @@ -398,6 +406,12 @@ static INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARA case WM_HELP: callback(dialog, TDN_HELP, 0, 0); return TRUE; + case WM_DESTROY: + callback(dialog, TDN_DESTROYED, 0, 0); + return FALSE; + case WM_CLOSE: + click_button(hwndDlg, dialog, IDCANCEL); + return FALSE; /* Custom messages*/ @@ -613,7 +627,12 @@ HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *pTaskConfig, int *pnBu header.title = empty_string; /* FIXME: Set to exe path instead */ header.titleSize = STR_SIZE(header.title); - header.template.style = DS_MODALFRAME | WS_CAPTION | WS_VISIBLE; + header.template.style = DS_MODALFRAME | WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE; + if(dialog->has_cancel) + header.template.style |= WS_SYSMENU; + if(pTaskConfig->dwFlags & TDF_CAN_BE_MINIMIZED) + header.template.style |= WS_SYSMENU | WS_MINIMIZEBOX; + header.template.cdit = list_count(controls); /* TaskDialogs are always desktop centered */ @@ -622,6 +641,7 @@ HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *pTaskConfig, int *pnBu header.template.x = (desktop.right - dialog_width)/2; header.template.y = (desktop.bottom - dialog_height)/2; + /* Turn template information into a dialog template to display it */ template_data = dialog_template_create(header, controls); diff --git a/dlls/comctl32/tests/taskdialog.c b/dlls/comctl32/tests/taskdialog.c index 7d6429c9c6..95ffe50eea 100644 --- a/dlls/comctl32/tests/taskdialog.c +++ b/dlls/comctl32/tests/taskdialog.c @@ -137,6 +137,15 @@ static const message_data mes_help[] = { { TDN_NO_MORE_MESSAGES } }; +static const message_data mes_cancel_ok_button_press[] = { + { TDN_DIALOG_CONSTRUCTED, 0, 0 }, + { TDN_CREATED, 0, 0 }, + { TDN_BUTTON_CLICKED, IDCANCEL, 0, S_FALSE, 1 }, + { TDN_BUTTON_CLICKED, IDOK, 0, S_OK }, + { TDN_DESTROYED, 0, 0 }, + { TDN_NO_MORE_MESSAGES } +}; + /* Message lists to send */ static const message_send_data mes_send_return[] = { @@ -201,6 +210,40 @@ static const message_send_data mes_send_F1[] = { { 0 } }; +static const message_send_data mes_send_esc[] = { + { WM_KEYDOWN, VK_ESCAPE, 0 }, + { 0 } +}; + +static const message_send_data mes_send_close[] = { + { WM_CLOSE, 0, 0 }, + { 0 } +}; + +static const message_send_data mes_send_esc_return[] = { + { WM_KEYDOWN, VK_ESCAPE, 0 }, + { WM_KEYDOWN, VK_RETURN, 0 }, + { 0 } +}; + +static const message_send_data mes_send_close_return[] = { + { WM_CLOSE, 0, 0 }, + { WM_KEYDOWN, VK_RETURN, 0 }, + { 0 } +}; + +static const message_send_data mes_send_esc_ok_cancel[] = { + { WM_KEYDOWN, VK_ESCAPE, 0, NULL, SEND_SYNCRONIZED }, + { TDM_CLICK_BUTTON, IDOK, 0 }, + { 0 } +}; + +static const message_send_data mes_send_close_ok_cancel[] = { + { WM_CLOSE, 0, 0, NULL, SEND_SYNCRONIZED }, + { TDM_CLICK_BUTTON, IDOK, 0 }, + { 0 } +}; + /* Our only way to get a button handle, since GetDlgItem and FindWindowEx don't work for the official taskdialog */ static HWND taskdialog_child; @@ -531,6 +574,44 @@ static void test_TaskDialogIndirect(void) /* Test TDM_HELP */ run_test(&info, IDOK, 0, 0, mes_help, mes_send_F1); + + /* Test ability to cancel dialog */ + + /* Test with TDF_ALLOW_DIALOG_CANCELLATION and without cancel button */ + info.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION; + info.dwCommonButtons = TDCBF_OK_BUTTON; + run_test(&info, IDCANCEL, 0, 0, mes_button_clicked_cancel, mes_send_esc); + run_test(&info, IDCANCEL, 0, 0, mes_button_clicked_cancel, mes_send_close); + + /* Test with TDF_ALLOW_DIALOG_CANCELLATION and without cancel button */ + info.dwFlags = TDF_CAN_BE_MINIMIZED; + info.dwCommonButtons = TDCBF_OK_BUTTON; + run_test(&info, IDCANCEL, 0, 0, mes_button_clicked_cancel, mes_send_esc); + run_test(&info, IDCANCEL, 0, 0, mes_button_clicked_cancel, mes_send_close); + + /* Test without allow-cancel flag and with cancel button */ + info.dwFlags = 0; + info.dwCommonButtons = TDCBF_OK_BUTTON | TDCBF_CANCEL_BUTTON; + run_test(&info, IDCANCEL, 0, 0, mes_button_clicked_cancel, mes_send_esc); + run_test(&info, IDCANCEL, 0, 0, mes_button_clicked_cancel, mes_send_close); + + /* Test without allow-cancel flag and without cancel button */ + info.dwFlags = 0; + info.dwCommonButtons = TDCBF_OK_BUTTON; + run_test(&info, IDOK, 0, 0, mes_button_clicked_ok, mes_send_esc_return); + run_test(&info, IDOK, 0, 0, mes_button_clicked_ok, mes_send_close_return); + + /* Test if the callback can disable the cancellation with cancel button */ + info.dwFlags = 0; + info.dwCommonButtons = TDCBF_OK_BUTTON | TDCBF_CANCEL_BUTTON; + run_test(&info, IDOK, 0, 0, mes_cancel_ok_button_press, mes_send_esc_ok_cancel); + run_test(&info, IDOK, 0, 0, mes_cancel_ok_button_press, mes_send_close_ok_cancel); + + /* Test if the callback can disable the cancellation without cancel button */ + info.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION; + info.dwCommonButtons = TDCBF_OK_BUTTON; + run_test(&info, IDOK, 0, 0, mes_cancel_ok_button_press, mes_send_esc_ok_cancel); + run_test(&info, IDOK, 0, 0, mes_cancel_ok_button_press, mes_send_close_ok_cancel); } START_TEST(taskdialog) -- 2.11.1