Commit cb468b68 authored by Zhiyi Zhang's avatar Zhiyi Zhang Committed by Alexandre Julliard

comctl32/taskdialog: Add support for command links.

parent 4836727d
...@@ -60,6 +60,8 @@ struct taskdialog_info ...@@ -60,6 +60,8 @@ struct taskdialog_info
HWND progress_bar; HWND progress_bar;
HWND *radio_buttons; HWND *radio_buttons;
INT radio_button_count; INT radio_button_count;
HWND *command_links;
INT command_link_count;
HWND *buttons; HWND *buttons;
INT button_count; INT button_count;
HWND default_button; HWND default_button;
...@@ -184,7 +186,8 @@ static HWND taskdialog_find_button(HWND *buttons, INT count, INT id) ...@@ -184,7 +186,8 @@ static HWND taskdialog_find_button(HWND *buttons, INT count, INT id)
static void taskdialog_enable_button(const struct taskdialog_info *dialog_info, INT id, BOOL enable) static void taskdialog_enable_button(const struct taskdialog_info *dialog_info, INT id, BOOL enable)
{ {
HWND hwnd = taskdialog_find_button(dialog_info->buttons, dialog_info->button_count, id); HWND hwnd = taskdialog_find_button(dialog_info->command_links, dialog_info->command_link_count, id);
if (!hwnd) hwnd = taskdialog_find_button(dialog_info->buttons, dialog_info->button_count, id);
if (hwnd) EnableWindow(hwnd, enable); if (hwnd) EnableWindow(hwnd, enable);
} }
...@@ -253,6 +256,11 @@ static BOOL taskdialog_hyperlink_enabled(struct taskdialog_info *dialog_info) ...@@ -253,6 +256,11 @@ static BOOL taskdialog_hyperlink_enabled(struct taskdialog_info *dialog_info)
return dialog_info->taskconfig->dwFlags & TDF_ENABLE_HYPERLINKS; return dialog_info->taskconfig->dwFlags & TDF_ENABLE_HYPERLINKS;
} }
static BOOL taskdialog_use_command_link(struct taskdialog_info *dialog_info)
{
return dialog_info->taskconfig->dwFlags & (TDF_USE_COMMAND_LINKS | TDF_USE_COMMAND_LINKS_NO_ICON);
}
static void taskdialog_get_label_size(struct taskdialog_info *dialog_info, HWND hwnd, LONG max_width, SIZE *size, static void taskdialog_get_label_size(struct taskdialog_info *dialog_info, HWND hwnd, LONG max_width, SIZE *size,
BOOL syslink) BOOL syslink)
{ {
...@@ -486,6 +494,34 @@ static void taskdialog_add_radio_buttons(struct taskdialog_info *dialog_info) ...@@ -486,6 +494,34 @@ static void taskdialog_add_radio_buttons(struct taskdialog_info *dialog_info)
} }
} }
static void taskdialog_add_command_links(struct taskdialog_info *dialog_info)
{
const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
DWORD default_style = BS_MULTILINE | BS_LEFT | BS_TOP | WS_CHILD | WS_VISIBLE | WS_TABSTOP, style;
BOOL is_default;
WCHAR *textW;
INT i;
if (!taskconfig->cButtons || !taskconfig->pButtons || !taskdialog_use_command_link(dialog_info)) return;
dialog_info->command_links = Alloc(taskconfig->cButtons * sizeof(*dialog_info->command_links));
if (!dialog_info->command_links) return;
dialog_info->command_link_count = taskconfig->cButtons;
for (i = 0; i < dialog_info->command_link_count; i++)
{
is_default = taskconfig->pButtons[i].nButtonID == taskconfig->nDefaultButton;
style = is_default ? default_style | BS_DEFCOMMANDLINK : default_style | BS_COMMANDLINK;
textW = taskdialog_gettext(dialog_info, TRUE, taskconfig->pButtons[i].pszButtonText);
dialog_info->command_links[i] = CreateWindowW(WC_BUTTONW, textW, style, 0, 0, 0, 0, dialog_info->hwnd,
(HMENU)taskconfig->pButtons[i].nButtonID, 0, NULL);
SendMessageW(dialog_info->command_links[i], WM_SETFONT, (WPARAM)dialog_info->font, 0);
Free(textW);
if (is_default && !dialog_info->default_button) dialog_info->default_button = dialog_info->command_links[i];
}
}
static void taskdialog_add_button(struct taskdialog_info *dialog_info, HWND *button, INT_PTR id, const WCHAR *text, static void taskdialog_add_button(struct taskdialog_info *dialog_info, HWND *button, INT_PTR id, const WCHAR *text,
BOOL custom_button) BOOL custom_button)
{ {
...@@ -504,17 +540,18 @@ static void taskdialog_add_button(struct taskdialog_info *dialog_info, HWND *but ...@@ -504,17 +540,18 @@ static void taskdialog_add_button(struct taskdialog_info *dialog_info, HWND *but
static void taskdialog_add_buttons(struct taskdialog_info *dialog_info) static void taskdialog_add_buttons(struct taskdialog_info *dialog_info)
{ {
const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig; const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
BOOL use_command_links = taskdialog_use_command_link(dialog_info);
DWORD flags = taskconfig->dwCommonButtons; DWORD flags = taskconfig->dwCommonButtons;
INT count, max_count; INT count, max_count;
/* Allocate enough memory for the custom and the default buttons. Maximum 6 default buttons possible. */ /* Allocate enough memory for the custom and the default buttons. Maximum 6 default buttons possible. */
max_count = 6; max_count = 6;
if (taskconfig->cButtons && taskconfig->pButtons) max_count += taskconfig->cButtons; if (!use_command_links && taskconfig->cButtons && taskconfig->pButtons) max_count += taskconfig->cButtons;
dialog_info->buttons = Alloc(max_count * sizeof(*dialog_info->buttons)); dialog_info->buttons = Alloc(max_count * sizeof(*dialog_info->buttons));
if (!dialog_info->buttons) return; if (!dialog_info->buttons) return;
for (count = 0; count < taskconfig->cButtons; count++) for (count = 0; !use_command_links && count < taskconfig->cButtons; count++)
taskdialog_add_button(dialog_info, &dialog_info->buttons[count], taskconfig->pButtons[count].nButtonID, taskdialog_add_button(dialog_info, &dialog_info->buttons[count], taskconfig->pButtons[count].nButtonID,
taskconfig->pButtons[count].pszButtonText, TRUE); taskconfig->pButtons[count].pszButtonText, TRUE);
...@@ -532,7 +569,7 @@ static void taskdialog_add_buttons(struct taskdialog_info *dialog_info) ...@@ -532,7 +569,7 @@ static void taskdialog_add_buttons(struct taskdialog_info *dialog_info)
if (flags & TDCBF_CANCEL_BUTTON) TASKDIALOG_INIT_COMMON_BUTTON(CANCEL); if (flags & TDCBF_CANCEL_BUTTON) TASKDIALOG_INIT_COMMON_BUTTON(CANCEL);
if (flags & TDCBF_CLOSE_BUTTON) TASKDIALOG_INIT_COMMON_BUTTON(CLOSE); if (flags & TDCBF_CLOSE_BUTTON) TASKDIALOG_INIT_COMMON_BUTTON(CLOSE);
if (!count) TASKDIALOG_INIT_COMMON_BUTTON(OK); if (!count && !dialog_info->command_link_count) TASKDIALOG_INIT_COMMON_BUTTON(OK);
#undef TASKDIALOG_INIT_COMMON_BUTTON #undef TASKDIALOG_INIT_COMMON_BUTTON
dialog_info->button_count = count; dialog_info->button_count = count;
...@@ -621,6 +658,19 @@ static void taskdialog_layout(struct taskdialog_info *dialog_info) ...@@ -621,6 +658,19 @@ static void taskdialog_layout(struct taskdialog_info *dialog_info)
dialog_height = y + size.cy; dialog_height = y + size.cy;
} }
/* Command links */
for (i = 0; i < dialog_info->command_link_count; i++)
{
x = main_icon_right + h_spacing;
y = dialog_height + v_spacing;
taskdialog_get_label_size(dialog_info, dialog_info->command_links[i], dialog_width - x - h_spacing, &size, FALSE);
size.cx = dialog_width - x - h_spacing;
/* Add spacing */
size.cy += 4;
SetWindowPos(dialog_info->command_links[i], 0, x, y, size.cx, size.cy, SWP_NOZORDER);
dialog_height = y + size.cy;
}
dialog_height = max(dialog_height, main_icon_bottom); dialog_height = max(dialog_height, main_icon_bottom);
/* Common and custom buttons */ /* Common and custom buttons */
...@@ -756,9 +806,12 @@ static void taskdialog_init(struct taskdialog_info *dialog_info, HWND hwnd) ...@@ -756,9 +806,12 @@ static void taskdialog_init(struct taskdialog_info *dialog_info, HWND hwnd)
taskdialog_add_content(dialog_info); taskdialog_add_content(dialog_info);
taskdialog_add_progress_bar(dialog_info); taskdialog_add_progress_bar(dialog_info);
taskdialog_add_radio_buttons(dialog_info); taskdialog_add_radio_buttons(dialog_info);
taskdialog_add_command_links(dialog_info);
taskdialog_add_buttons(dialog_info); taskdialog_add_buttons(dialog_info);
/* Set default button */ /* Set default button */
if (!dialog_info->default_button && dialog_info->command_links)
dialog_info->default_button = dialog_info->command_links[0];
if (!dialog_info->default_button) dialog_info->default_button = dialog_info->buttons[0]; if (!dialog_info->default_button) dialog_info->default_button = dialog_info->buttons[0];
SendMessageW(dialog_info->hwnd, WM_NEXTDLGCTL, (WPARAM)dialog_info->default_button, TRUE); SendMessageW(dialog_info->hwnd, WM_NEXTDLGCTL, (WPARAM)dialog_info->default_button, TRUE);
id = GetWindowLongW(dialog_info->default_button, GWLP_ID); id = GetWindowLongW(dialog_info->default_button, GWLP_ID);
...@@ -774,6 +827,7 @@ static void taskdialog_destroy(struct taskdialog_info *dialog_info) ...@@ -774,6 +827,7 @@ static void taskdialog_destroy(struct taskdialog_info *dialog_info)
if (dialog_info->main_instruction_font) DeleteObject(dialog_info->main_instruction_font); if (dialog_info->main_instruction_font) DeleteObject(dialog_info->main_instruction_font);
if (dialog_info->buttons) Free(dialog_info->buttons); if (dialog_info->buttons) Free(dialog_info->buttons);
if (dialog_info->radio_buttons) Free(dialog_info->radio_buttons); if (dialog_info->radio_buttons) Free(dialog_info->radio_buttons);
if (dialog_info->command_links) Free(dialog_info->command_links);
} }
static INT_PTR CALLBACK taskdialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) static INT_PTR CALLBACK taskdialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
......
...@@ -323,7 +323,7 @@ static void test_callback(void) ...@@ -323,7 +323,7 @@ static void test_callback(void)
static void test_buttons(void) static void test_buttons(void)
{ {
TASKDIALOGCONFIG info = {0}; TASKDIALOGCONFIG info = {0};
static const DWORD command_link_flags[] = {0, TDF_USE_COMMAND_LINKS, TDF_USE_COMMAND_LINKS_NO_ICON};
TASKDIALOG_BUTTON custom_buttons[TEST_NUM_BUTTONS], radio_buttons[TEST_NUM_RADIO_BUTTONS]; TASKDIALOG_BUTTON custom_buttons[TEST_NUM_BUTTONS], radio_buttons[TEST_NUM_RADIO_BUTTONS];
const WCHAR button_format[] = {'%','0','2','d',0}; const WCHAR button_format[] = {'%','0','2','d',0};
/* Each button has two digits as title, plus null-terminator */ /* Each button has two digits as title, plus null-terminator */
...@@ -373,31 +373,40 @@ static void test_buttons(void) ...@@ -373,31 +373,40 @@ static void test_buttons(void)
info.dwCommonButtons = TDCBF_CANCEL_BUTTON | TDCBF_CLOSE_BUTTON; 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, msg_return_press_cancel, "default button: unset default");
/* Test with all common and custom buttons and invalid default ID */ /* Custom buttons could be command links */
info.nDefaultButton = 0xff; /* Random ID, should also default to first created button */ for (i = 0; i < ARRAY_SIZE(command_link_flags); i++)
info.cButtons = TEST_NUM_BUTTONS; {
info.pButtons = custom_buttons; info.dwFlags = command_link_flags[i];
run_test(&info, ID_START_BUTTON, 0, msg_return_press_custom1, "default button: invalid default, with common buttons - 1");
/* Test with all common and custom buttons and invalid default ID */
info.nDefaultButton = -1; /* Should work despite button ID -1 */ info.nDefaultButton = 0xff; /* Random ID, should also default to first created button */
run_test(&info, -1, 0, msg_return_press_custom10, "default button: invalid default, with common buttons - 2"); info.cButtons = TEST_NUM_BUTTONS;
info.pButtons = custom_buttons;
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, msg_return_press_custom1, "default button: invalid default, with common buttons - 3"); "default button: invalid default, with common buttons - 1");
/* Test with only custom buttons and invalid default ID */ info.nDefaultButton = -1; /* Should work despite button ID -1 */
info.dwCommonButtons = 0; run_test(&info, -1, 0, msg_return_press_custom10, "default button: invalid default, with common buttons - 2");
run_test(&info, ID_START_BUTTON, 0, msg_return_press_custom1, "default button: invalid default, no common buttons");
info.nDefaultButton = -2; /* Should also default to first created button */
/* Test with common and custom buttons and valid default ID */ run_test(&info, ID_START_BUTTON, 0, msg_return_press_custom1,
info.dwCommonButtons = TDCBF_OK_BUTTON | TDCBF_YES_BUTTON | TDCBF_NO_BUTTON "default button: invalid default, with common buttons - 3");
| TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON;
info.nDefaultButton = IDRETRY; /* Test with only custom buttons and invalid default ID */
run_test(&info, IDRETRY, 0, msg_return_press_retry, "default button: valid default - 1"); info.dwCommonButtons = 0;
run_test(&info, ID_START_BUTTON, 0, msg_return_press_custom1,
/* Test with common and custom buttons and valid default ID */ "default button: invalid default, no common buttons");
info.nDefaultButton = ID_START_BUTTON + 3;
run_test(&info, ID_START_BUTTON + 3, 0, msg_return_press_custom4, "default button: valid default - 2"); /* 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");
}
/* Test radio buttons */ /* Test radio buttons */
info.nDefaultButton = 0; info.nDefaultButton = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment