mirror of
https://github.com/reactos/wine.git
synced 2024-12-04 09:53:54 +00:00
comctl32/taskdialog: Added support for nDefaultButton.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
afbd598ac1
commit
32c42cc109
@ -59,6 +59,15 @@ struct taskdialog_control
|
||||
unsigned int template_size;
|
||||
};
|
||||
|
||||
struct taskdialog_button_desc
|
||||
{
|
||||
int id;
|
||||
const WCHAR *text;
|
||||
unsigned int width;
|
||||
unsigned int line;
|
||||
HINSTANCE hinst;
|
||||
};
|
||||
|
||||
struct taskdialog_template_desc
|
||||
{
|
||||
const TASKDIALOGCONFIG *taskconfig;
|
||||
@ -69,15 +78,7 @@ struct taskdialog_template_desc
|
||||
LONG x_baseunit;
|
||||
LONG y_baseunit;
|
||||
HFONT font;
|
||||
};
|
||||
|
||||
struct taskdialog_button_desc
|
||||
{
|
||||
int id;
|
||||
const WCHAR *text;
|
||||
unsigned int width;
|
||||
unsigned int line;
|
||||
HINSTANCE hinst;
|
||||
struct taskdialog_button_desc *default_button;
|
||||
};
|
||||
|
||||
struct taskdialog_info
|
||||
@ -151,7 +152,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 +179,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 +207,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;
|
||||
@ -234,6 +235,9 @@ static void taskdialog_init_button(struct taskdialog_button_desc *button, struct
|
||||
button->width = max(DIALOG_BUTTON_WIDTH, sz.cx + DIALOG_SPACING * 2);
|
||||
button->line = 0;
|
||||
button->hinst = custom_button ? desc->taskconfig->hInstance : COMCTL32_hModule;
|
||||
|
||||
if (id == desc->taskconfig->nDefaultButton)
|
||||
desc->default_button = button;
|
||||
}
|
||||
|
||||
static void taskdialog_init_common_buttons(struct taskdialog_template_desc *desc, struct taskdialog_button_desc *buttons,
|
||||
@ -290,6 +294,9 @@ static unsigned int taskdialog_add_buttons(struct taskdialog_template_desc *desc
|
||||
if (count == 0)
|
||||
taskdialog_init_button(&buttons[count++], desc, IDOK, MAKEINTRESOURCEW(IDS_BUTTON_OK), FALSE);
|
||||
|
||||
if (!desc->default_button)
|
||||
desc->default_button = &buttons[0];
|
||||
|
||||
/* For easy handling just allocate as many lines as buttons, the worst case. */
|
||||
line_widths = Alloc(count * sizeof(*line_widths));
|
||||
|
||||
@ -344,14 +351,16 @@ static unsigned int taskdialog_add_buttons(struct taskdialog_template_desc *desc
|
||||
location_x = alignment;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
DWORD style = &buttons[i] == desc->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;
|
||||
}
|
||||
@ -464,6 +473,7 @@ static DLGTEMPLATE *create_taskdialog_template(const TASKDIALOGCONFIG *taskconfi
|
||||
desc.dialog_height = 0;
|
||||
desc.dialog_width = max(taskconfig->cxWidth, DIALOG_MIN_WIDTH);
|
||||
desc.dialog_width = min(desc.dialog_width, screen_width);
|
||||
desc.default_button = NULL;
|
||||
|
||||
size += taskdialog_add_main_instruction(&desc);
|
||||
size += taskdialog_add_content(&desc);
|
||||
@ -578,7 +588,7 @@ HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *taskconfig, int *butto
|
||||
dialog_info.callback_data = taskconfig->lpCallbackData;
|
||||
|
||||
template = create_taskdialog_template(taskconfig);
|
||||
ret = DialogBoxIndirectParamW(taskconfig->hInstance, template, taskconfig->hwndParent,
|
||||
ret = (short)DialogBoxIndirectParamW(taskconfig->hInstance, template, taskconfig->hwndParent,
|
||||
taskdialog_proc, (LPARAM)&dialog_info);
|
||||
Free(template);
|
||||
|
||||
|
@ -33,6 +33,11 @@
|
||||
#define NUM_MSG_SEQUENCES 1
|
||||
#define TASKDIALOG_SEQ_INDEX 0
|
||||
|
||||
#define TEST_NUM_BUTTONS 10 /* 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,55 @@ 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 const struct message_info msg_return_press_custom10[] =
|
||||
{
|
||||
{ TDN_CREATED, 0, 0, S_OK, msg_send_return },
|
||||
{ TDN_BUTTON_CLICKED, -1, 0, S_OK, NULL },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static void init_test_message(UINT message, WPARAM wParam, LPARAM lParam, struct message *msg)
|
||||
{
|
||||
msg->message = WM_TD_CALLBACK;
|
||||
@ -76,11 +130,11 @@ static void init_test_message(UINT message, WPARAM wParam, LPARAM lParam, struct
|
||||
msg->stage = 0;
|
||||
}
|
||||
|
||||
#define run_test(info, expect_button, expect_radio, seq, context) \
|
||||
run_test_(info, expect_button, expect_radio, seq, context, \
|
||||
#define run_test(info, expect_button, seq, context) \
|
||||
run_test_(info, expect_button, seq, context, \
|
||||
sizeof(seq)/sizeof(seq[0]) - 1, __FILE__, __LINE__)
|
||||
|
||||
void run_test_(TASKDIALOGCONFIG *info, int expect_button, int expect_radio, const struct message_info *test_messages,
|
||||
void run_test_(TASKDIALOGCONFIG *info, int expect_button, const struct message_info *test_messages,
|
||||
const char *context, int test_messages_len, const char *file, int line)
|
||||
{
|
||||
struct message *msg, *msg_start;
|
||||
@ -108,8 +162,6 @@ void run_test_(TASKDIALOGCONFIG *info, int expect_button, int expect_radio, cons
|
||||
ok_sequence_(sequences, TASKDIALOG_SEQ_INDEX, msg_start, context, FALSE, file, line);
|
||||
ok_(file, line)(ret_button == expect_button,
|
||||
"Wrong button. Expected %d, got %d\n", expect_button, ret_button);
|
||||
ok_(file, line)(ret_radio == expect_radio,
|
||||
"Wrong radio button. Expected %d, got %d\n", expect_radio, ret_radio);
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, msg_start);
|
||||
}
|
||||
@ -125,7 +177,7 @@ static HRESULT CALLBACK taskdialog_callback_proc(HWND hwnd, UINT notification,
|
||||
|
||||
ok(test_ref_data == ref_data, "Unexpected ref data %lu.\n", ref_data);
|
||||
|
||||
init_test_message(notification, wParam, lParam, &msg);
|
||||
init_test_message(notification, (short)wParam, lParam, &msg);
|
||||
add_message(sequences, TASKDIALOG_SEQ_INDEX, &msg);
|
||||
|
||||
if (notification == TDN_DIALOG_CONSTRUCTED || notification == TDN_DESTROYED) /* Skip implicit messages */
|
||||
@ -167,7 +219,75 @@ 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, msg_return_press_ok, "Press VK_RETURN.");
|
||||
}
|
||||
|
||||
static void test_buttons(void)
|
||||
{
|
||||
TASKDIALOGCONFIG info = {0};
|
||||
|
||||
TASKDIALOG_BUTTON custom_buttons[TEST_NUM_BUTTONS];
|
||||
const WCHAR button_format[] = {'%','0','2','d',0};
|
||||
WCHAR button_titles[TEST_NUM_BUTTONS * 3]; /* Each button has two digits as title, plus null-terminator */
|
||||
int i;
|
||||
|
||||
info.cbSize = sizeof(TASKDIALOGCONFIG);
|
||||
info.pfCallback = taskdialog_callback_proc;
|
||||
info.lpCallbackData = test_ref_data;
|
||||
|
||||
/* Init custom buttons */
|
||||
for (i = 0; i < TEST_NUM_BUTTONS; i++)
|
||||
{
|
||||
WCHAR *text = &button_titles[i * 3];
|
||||
wsprintfW(text, button_format, i);
|
||||
|
||||
custom_buttons[i].pszButtonText = text;
|
||||
custom_buttons[i].nButtonID = ID_START_BUTTON + i;
|
||||
}
|
||||
custom_buttons[TEST_NUM_BUTTONS - 1].nButtonID = -1;
|
||||
|
||||
/* 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, 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, 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, msg_return_press_no, "default button: unset default");
|
||||
info.dwCommonButtons = TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON;
|
||||
run_test(&info, IDRETRY, msg_return_press_retry, "default button: unset default");
|
||||
info.dwCommonButtons = TDCBF_CANCEL_BUTTON | TDCBF_CLOSE_BUTTON;
|
||||
run_test(&info, IDCANCEL, 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 = TEST_NUM_BUTTONS;
|
||||
info.pButtons = custom_buttons;
|
||||
run_test(&info, ID_START_BUTTON, 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, 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, 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, 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, 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, msg_return_press_custom4, "default button: valid default - 2");
|
||||
}
|
||||
|
||||
START_TEST(taskdialog)
|
||||
@ -205,6 +325,7 @@ START_TEST(taskdialog)
|
||||
|
||||
test_invalid_parameters();
|
||||
test_callback();
|
||||
test_buttons();
|
||||
|
||||
unload_v6_module(ctx_cookie, hCtx);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user