[PATCH v2 4/6] comctl32/taskdialog: Add support for verification box.
Zhiyi Zhang
zzhang at codeweavers.com
Wed Jul 18 22:04:24 CDT 2018
Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
dlls/comctl32/taskdialog.c | 58 ++++++++++++-
dlls/comctl32/tests/taskdialog.c | 136 +++++++++++++++++++++++++------
2 files changed, 166 insertions(+), 28 deletions(-)
diff --git a/dlls/comctl32/taskdialog.c b/dlls/comctl32/taskdialog.c
index 54ad58b340..411b8e9212 100644
--- a/dlls/comctl32/taskdialog.c
+++ b/dlls/comctl32/taskdialog.c
@@ -66,6 +66,7 @@ struct taskdialog_info
INT command_link_count;
HWND expanded_info;
HWND expando_button;
+ HWND verification_box;
HWND *buttons;
INT button_count;
HWND default_button;
@@ -78,6 +79,7 @@ struct taskdialog_info
LONG v_spacing;
} m;
INT selected_radio_id;
+ BOOL verification_checked;
BOOL expanded;
WCHAR *expanded_text;
WCHAR *collapsed_text;
@@ -247,6 +249,13 @@ static void taskdialog_on_button_click(struct taskdialog_info *dialog_info, HWND
return;
}
+ if (hwnd == dialog_info->verification_box)
+ {
+ dialog_info->verification_checked = !dialog_info->verification_checked;
+ taskdialog_notify(dialog_info, TDN_VERIFICATION_CLICKED, dialog_info->verification_checked, 0);
+ return;
+ }
+
radio_button = taskdialog_find_button(dialog_info->radio_buttons, dialog_info->radio_button_count, command_id);
if (radio_button)
{
@@ -636,6 +645,26 @@ static void taskdialog_add_expando_button(struct taskdialog_info *dialog_info)
SendMessageW(dialog_info->expando_button, WM_SETFONT, (WPARAM)dialog_info->font, 0);
}
+static void taskdialog_add_verification_box(struct taskdialog_info *dialog_info)
+{
+ const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
+ static const DWORD style = BS_AUTOCHECKBOX | BS_MULTILINE | BS_LEFT | BS_TOP | WS_CHILD | WS_VISIBLE | WS_TABSTOP;
+ WCHAR *textW;
+
+ /* TDF_VERIFICATION_FLAG_CHECKED works even if pszVerificationText is not set */
+ if (taskconfig->dwFlags & TDF_VERIFICATION_FLAG_CHECKED) dialog_info->verification_checked = TRUE;
+
+ if (!taskconfig->pszVerificationText) return;
+
+ textW = taskdialog_gettext(dialog_info, TRUE, taskconfig->pszVerificationText);
+ dialog_info->verification_box = CreateWindowW(WC_BUTTONW, textW, style, 0, 0, 0, 0, dialog_info->hwnd, 0, 0, 0);
+ SendMessageW(dialog_info->verification_box, WM_SETFONT, (WPARAM)dialog_info->font, 0);
+ Free(textW);
+
+ if (taskconfig->dwFlags & TDF_VERIFICATION_FLAG_CHECKED)
+ SendMessageW(dialog_info->verification_box, BM_SETCHECK, BST_CHECKED, 0);
+}
+
static void taskdialog_add_button(struct taskdialog_info *dialog_info, HWND *button, INT_PTR id, const WCHAR *text,
BOOL custom_button)
{
@@ -806,6 +835,19 @@ static void taskdialog_layout(struct taskdialog_info *dialog_info)
expando_bottom = y + size.cy;
}
+ /* Verification box */
+ if (dialog_info->verification_box)
+ {
+ x = h_spacing;
+ y = expando_bottom + v_spacing;
+ size.cx = DIALOG_MIN_WIDTH / 2;
+ taskdialog_du_to_px(dialog_info, &size.cx, NULL);
+ taskdialog_get_radio_button_size(dialog_info, dialog_info->verification_box, size.cx, &size);
+ SetWindowPos(dialog_info->verification_box, 0, x, y, size.cx, size.cy, SWP_NOZORDER);
+ expando_right = max(expando_right, x + size.cx);
+ expando_bottom = y + size.cy;
+ }
+
/* Common and custom buttons */
button_layout_infos = Alloc(dialog_info->button_count * sizeof(*button_layout_infos));
line_widths = Alloc(dialog_info->button_count * sizeof(*line_widths));
@@ -983,6 +1025,7 @@ static void taskdialog_init(struct taskdialog_info *dialog_info, HWND hwnd)
taskdialog_add_radio_buttons(dialog_info);
taskdialog_add_command_links(dialog_info);
taskdialog_add_expando_button(dialog_info);
+ taskdialog_add_verification_box(dialog_info);
taskdialog_add_buttons(dialog_info);
/* Set default button */
@@ -1063,6 +1106,19 @@ static INT_PTR CALLBACK taskdialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPAR
case TDM_ENABLE_RADIO_BUTTON:
taskdialog_enable_radio_button(dialog_info, wParam, lParam);
break;
+ case TDM_CLICK_VERIFICATION:
+ {
+ BOOL checked = (BOOL)wParam;
+ BOOL focused = (BOOL)lParam;
+ dialog_info->verification_checked = checked;
+ if (dialog_info->verification_box)
+ {
+ SendMessageW(dialog_info->verification_box, BM_SETCHECK, checked ? BST_CHECKED : BST_UNCHECKED, 0);
+ taskdialog_notify(dialog_info, TDN_VERIFICATION_CLICKED, checked, 0);
+ if (focused) SetFocus(dialog_info->verification_box);
+ }
+ break;
+ }
case WM_INITDIALOG:
dialog_info = (struct taskdialog_info *)lParam;
@@ -1151,7 +1207,7 @@ HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *taskconfig, int *butto
if (button) *button = ret;
if (radio_button) *radio_button = dialog_info.selected_radio_id;
- if (verification_flag_checked) *verification_flag_checked = TRUE;
+ if (verification_flag_checked) *verification_flag_checked = dialog_info.verification_checked;
return S_OK;
}
diff --git a/dlls/comctl32/tests/taskdialog.c b/dlls/comctl32/tests/taskdialog.c
index 7fb8f3dcfc..8d60fb2eb8 100644
--- a/dlls/comctl32/tests/taskdialog.c
+++ b/dlls/comctl32/tests/taskdialog.c
@@ -229,6 +229,48 @@ static const struct message_info msg_return_press_negative_id_radio_button[] =
{ 0 }
};
+static const struct message_info msg_return_default_verification_unchecked[] =
+{
+ { TDN_CREATED, 0, 0, S_OK, msg_send_click_ok },
+ { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
+ { 0 }
+};
+
+static const struct message_info msg_return_default_verification_checked[] =
+{
+ { TDN_CREATED, 0, 0, S_OK, msg_send_click_ok },
+ { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
+ { 0 }
+};
+
+static const struct message_info msg_uncheck_verification[] =
+{
+ { TDM_CLICK_VERIFICATION, FALSE, 0 },
+ { 0 }
+};
+
+static const struct message_info msg_return_verification_unchecked[] =
+{
+ { TDN_CREATED, 0, 0, S_OK, msg_uncheck_verification },
+ { TDN_VERIFICATION_CLICKED, FALSE, 0, S_OK, msg_send_click_ok },
+ { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
+ { 0 }
+};
+
+static const struct message_info msg_check_verification[] =
+{
+ { TDM_CLICK_VERIFICATION, TRUE, 0 },
+ { 0 }
+};
+
+static const struct message_info msg_return_verification_checked[] =
+{
+ { TDN_CREATED, 0, 0, S_OK, msg_check_verification },
+ { TDN_VERIFICATION_CLICKED, TRUE, 0, S_OK, msg_send_click_ok },
+ { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
+ { 0 }
+};
+
static void init_test_message(UINT message, WPARAM wParam, LPARAM lParam, struct message *msg)
{
msg->message = WM_TD_CALLBACK;
@@ -239,17 +281,18 @@ static void init_test_message(UINT message, WPARAM wParam, LPARAM lParam, struct
msg->stage = 0;
}
-#define run_test(info, expect_button, expect_radio_button, seq, context) \
- run_test_(info, expect_button, expect_radio_button, seq, context, \
- ARRAY_SIZE(seq) - 1, __FILE__, __LINE__)
+#define run_test(info, expect_button, expect_radio_button, verification_checked, seq, context) \
+ run_test_(info, expect_button, expect_radio_button, verification_checked, seq, context, \
+ ARRAY_SIZE(seq) - 1, __FILE__, __LINE__)
-static void run_test_(TASKDIALOGCONFIG *info, int expect_button, int expect_radio_button,
+static void run_test_(TASKDIALOGCONFIG *info, int expect_button, int expect_radio_button, BOOL verification_checked,
const struct message_info *test_messages, const char *context, int test_messages_len,
const char *file, int line)
{
struct message *msg, *msg_start;
int ret_button = 0;
int ret_radio = 0;
+ BOOL ret_verification = FALSE;
HRESULT hr;
int i;
@@ -266,7 +309,7 @@ static void run_test_(TASKDIALOGCONFIG *info, int expect_button, int expect_radi
current_message_info = test_messages;
flush_sequences(sequences, NUM_MSG_SEQUENCES);
- hr = pTaskDialogIndirect(info, &ret_button, &ret_radio, NULL);
+ hr = pTaskDialogIndirect(info, &ret_button, &ret_radio, &ret_verification);
ok_(file, line)(hr == S_OK, "TaskDialogIndirect() failed, got %#x.\n", hr);
ok_sequence_(sequences, TASKDIALOG_SEQ_INDEX, msg_start, context, FALSE, file, line);
@@ -331,7 +374,7 @@ static void test_callback(void)
info.pfCallback = taskdialog_callback_proc;
info.lpCallbackData = test_ref_data;
- run_test(&info, IDOK, 0, msg_return_press_ok, "Press VK_RETURN.");
+ run_test(&info, IDOK, 0, FALSE, msg_return_press_ok, "Press VK_RETURN.");
}
static void test_buttons(void)
@@ -376,16 +419,16 @@ static void test_buttons(void)
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");
+ run_test(&info, IDOK, 0, FALSE, 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");
+ run_test(&info, IDYES, 0, FALSE, 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");
+ run_test(&info, IDNO, 0, FALSE, 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");
+ run_test(&info, IDRETRY, 0, FALSE, 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");
+ run_test(&info, IDCANCEL, 0, FALSE, msg_return_press_cancel, "default button: unset default");
/* Custom buttons could be command links */
for (i = 0; i < ARRAY_SIZE(command_link_flags); i++)
@@ -396,30 +439,30 @@ static void test_buttons(void)
info.nDefaultButton = 0xff; /* Random ID, should also default to first created button */
info.cButtons = TEST_NUM_BUTTONS;
info.pButtons = custom_buttons;
- run_test(&info, ID_START_BUTTON, 0, msg_return_press_custom1,
+ run_test(&info, ID_START_BUTTON, 0, FALSE, msg_return_press_custom1,
"default button: invalid default, with common buttons - 1");
info.nDefaultButton = -1; /* Should work despite button ID -1 */
- run_test(&info, -1, 0, msg_return_press_custom10, "default button: invalid default, with common buttons - 2");
+ run_test(&info, -1, 0, FALSE, msg_return_press_custom10, "default button: invalid default, with common buttons - 2");
info.nDefaultButton = -2; /* Should also default to first created button */
- run_test(&info, ID_START_BUTTON, 0, msg_return_press_custom1,
+ run_test(&info, ID_START_BUTTON, 0, FALSE, msg_return_press_custom1,
"default button: invalid default, with common buttons - 3");
/* Test with only custom buttons and invalid default ID */
info.dwCommonButtons = 0;
- run_test(&info, ID_START_BUTTON, 0, msg_return_press_custom1,
+ run_test(&info, ID_START_BUTTON, 0, FALSE, 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");
+ run_test(&info, IDRETRY, 0, FALSE, 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");
+ run_test(&info, ID_START_BUTTON + 3, 0, FALSE, msg_return_press_custom4, "default button: valid default - 2");
}
/* Test radio buttons */
@@ -431,44 +474,52 @@ static void test_buttons(void)
info.pRadioButtons = radio_buttons;
/* Test default first radio button */
- run_test(&info, IDOK, ID_START_RADIO_BUTTON, msg_return_default_radio_button_1, "default radio button: default first radio button");
+ run_test(&info, IDOK, ID_START_RADIO_BUTTON, FALSE, msg_return_default_radio_button_1,
+ "default radio button: default first radio button");
/* Test default radio button */
info.nDefaultRadioButton = ID_START_RADIO_BUTTON + 1;
- run_test(&info, IDOK, info.nDefaultRadioButton, msg_return_default_radio_button_2, "default radio button: default radio button");
+ run_test(&info, IDOK, info.nDefaultRadioButton, FALSE, msg_return_default_radio_button_2,
+ "default radio button: default radio button");
/* Test default radio button with -2 */
info.nDefaultRadioButton = -2;
- run_test(&info, IDOK, info.nDefaultRadioButton, msg_return_default_radio_button_3, "default radio button: default radio button with id -2");
+ run_test(&info, IDOK, info.nDefaultRadioButton, FALSE, msg_return_default_radio_button_3,
+ "default radio button: default radio button with id -2");
/* Test default radio button after clicking the first, messages still work even radio button is disabled */
info.nDefaultRadioButton = ID_START_RADIO_BUTTON + 1;
- run_test(&info, IDOK, ID_START_RADIO_BUTTON, msg_return_first_radio_button, "default radio button: radio button after clicking");
+ run_test(&info, IDOK, ID_START_RADIO_BUTTON, FALSE, msg_return_first_radio_button,
+ "default radio button: radio button after clicking");
/* Test radio button after disabling and clicking the first */
info.nDefaultRadioButton = ID_START_RADIO_BUTTON + 1;
- run_test(&info, IDOK, ID_START_RADIO_BUTTON, msg_return_default_radio_button_clicking_disabled, "default radio button: disable radio button before clicking");
+ run_test(&info, IDOK, ID_START_RADIO_BUTTON, FALSE, msg_return_default_radio_button_clicking_disabled,
+ "default radio button: disable radio button before clicking");
/* Test no default radio button, TDF_NO_DEFAULT_RADIO_BUTTON is set, TDN_RADIO_BUTTON_CLICKED will still be received, just radio button not selected */
info.nDefaultRadioButton = ID_START_RADIO_BUTTON;
info.dwFlags = TDF_NO_DEFAULT_RADIO_BUTTON;
- run_test(&info, IDOK, info.nDefaultRadioButton, msg_return_no_default_radio_button_flag, "default radio button: no default radio flag");
+ run_test(&info, IDOK, info.nDefaultRadioButton, FALSE, msg_return_no_default_radio_button_flag,
+ "default radio button: no default radio flag");
/* Test no default radio button, TDF_NO_DEFAULT_RADIO_BUTTON is set and nDefaultRadioButton is 0.
* TDN_RADIO_BUTTON_CLICKED will not be sent, and just radio button not selected */
info.nDefaultRadioButton = 0;
info.dwFlags = TDF_NO_DEFAULT_RADIO_BUTTON;
- run_test(&info, IDOK, 0, msg_return_no_default_radio_button_id_and_flag, "default radio button: no default radio id and flag");
+ run_test(&info, IDOK, 0, FALSE, msg_return_no_default_radio_button_id_and_flag,
+ "default radio button: no default radio id and flag");
/* Test no default radio button, TDF_NO_DEFAULT_RADIO_BUTTON is set and nDefaultRadioButton is invalid.
* TDN_RADIO_BUTTON_CLICKED will not be sent, and just radio button not selected */
info.nDefaultRadioButton = 0xff;
info.dwFlags = TDF_NO_DEFAULT_RADIO_BUTTON;
- run_test(&info, IDOK, 0, msg_return_no_default_radio_button_id_and_flag, "default radio button: no default flag, invalid id");
+ run_test(&info, IDOK, 0, FALSE, msg_return_no_default_radio_button_id_and_flag,
+ "default radio button: no default flag, invalid id");
info.nDefaultRadioButton = 0;
info.dwFlags = TDF_NO_DEFAULT_RADIO_BUTTON;
- run_test(&info, IDOK, -2, msg_return_press_negative_id_radio_button,
+ run_test(&info, IDOK, -2, FALSE, msg_return_press_negative_id_radio_button,
"radio button: manually click radio button with negative id");
}
@@ -481,7 +532,7 @@ static void test_help(void)
info.lpCallbackData = test_ref_data;
info.dwCommonButtons = TDCBF_OK_BUTTON;
- run_test(&info, IDOK, 0, msg_got_tdn_help, "send f1");
+ run_test(&info, IDOK, 0, FALSE, msg_got_tdn_help, "send f1");
}
struct timer_notification_data
@@ -601,6 +652,36 @@ static void test_progress_bar(void)
pTaskDialogIndirect(&info, NULL, NULL, NULL);
}
+static void test_verification_box(void)
+{
+ TASKDIALOGCONFIG info = {0};
+ WCHAR textW[] = {'t', 'e', 'x', 't', 0};
+
+ info.cbSize = sizeof(TASKDIALOGCONFIG);
+ info.pfCallback = taskdialog_callback_proc;
+ info.lpCallbackData = test_ref_data;
+ info.dwCommonButtons = TDCBF_OK_BUTTON;
+
+ /* TDF_VERIFICATION_FLAG_CHECKED works even if pszVerificationText is not set */
+ run_test(&info, IDOK, 0, FALSE, msg_return_default_verification_unchecked, "default verification box: unchecked");
+
+ info.dwFlags = TDF_VERIFICATION_FLAG_CHECKED;
+ run_test(&info, IDOK, 0, FALSE, msg_return_default_verification_checked, "default verification box: checked");
+
+ info.pszVerificationText = textW;
+ run_test(&info, IDOK, 0, FALSE, msg_return_default_verification_unchecked, "default verification box: unchecked");
+
+ info.dwFlags = TDF_VERIFICATION_FLAG_CHECKED;
+ run_test(&info, IDOK, 0, FALSE, msg_return_default_verification_checked, "default verification box: checked");
+
+ run_test(&info, IDOK, 0, FALSE, msg_return_verification_unchecked,
+ "default verification box: default checked and then unchecked");
+
+ info.dwFlags = 0;
+ run_test(&info, IDOK, 0, FALSE, msg_return_verification_checked,
+ "default verification box: default unchecked and then checked");
+}
+
START_TEST(taskdialog)
{
ULONG_PTR ctx_cookie;
@@ -640,6 +721,7 @@ START_TEST(taskdialog)
test_help();
test_timer();
test_progress_bar();
+ test_verification_box();
unload_v6_module(ctx_cookie, hCtx);
}
--
2.18.0
More information about the wine-devel
mailing list